实例化一个 TypeVar 类型
Instantiate a type that is a TypeVar
作为一名 C++ 程序员,以下代码对我来说似乎很自然,但它并不 运行:
from typing import TypeVar, Generic, List, NewType
TPopMember = TypeVar('TPopMember')
Population = NewType('Population', List[TPopMember])
class EvolutionaryAlgorithm(Generic[TPopMember]):
def __init__(self, populationSize: int) -> None:
# The following raises TypeError: 'TypeVar' object is not callable
self.__population = Population([TPopMember() for _ in range(populationSize)])
显然 Python 无法实例化实际上是 TypeVars 的 类(TPopMember)。我只是想创建一个列表(人口),其中包含几个默认初始化(Python 中怎么说?)TPopMembers。我该怎么办?
我正在使用 Python 3.7.2.
您没有意识到类型提示是 提示。也就是说,根本不要认为它是一个类型。你不能实例化它们。
据我从您的评论中了解到,您的意图是执行 C++ 模板允许您执行的操作。所以这是我实现这一目标的方法:
from typing import TypeVar, Generic, List, NewType, Type
import random
class PopMember:
def __init__(self):
self.x = random.randint(0, 100)
def __repr__(self):
return "Pop({})".format(self.x)
TPopMember = TypeVar("TPopMember")
Population = NewType('Population', List[TPopMember])
class EvolutionaryAlgorithm(Generic[TPopMember]):
def __init__(self, member_class: Type[TPopMember], populationSize: int) -> None:
self.__population = Population([member_class() for _ in range(populationSize)])
def __repr__(self):
return "EA({})".format(self.__population)
x = EvolutionaryAlgorithm(PopMember, 5)
print(x)
输出:
EA([Pop(49), Pop(94), Pop(24), Pop(73), Pop(66)])
您必须了解的是,如果您从 Generic[T]
派生了 class,则在创建 class 时需要使用 T
一些方法。在我的示例中,我 创建一个虚拟对象并解析它的 class 并启动它。通常我不会这样写,我可以把 class 作为参数 传入 class 给构造函数来请求生成这种特定类型的项目,因为 class 本身与它的实例不同,也是一个 Python 对象。 (感谢 chepner 的建议)
您可以执行以下操作:
from typing import TypeVar, Generic, List, NewType
import random
class PopMember:
def __init__(self):
self.x = random.randint(0, 100)
def __repr__(self):
return "Pop({})".format(self.x)
TPopMember = TypeVar('TPopMember')
Population = NewType('Population', List[TPopMember])
class EvolutionaryAlgorithm(Generic[TPopMember]):
def __init__(self, populationSize: int) -> None:
obj = self.__orig_class__.__args__[0]
self.__population = Population([obj() for _ in range(populationSize)])
@property
def population(self):
return self.__population
evolution = EvolutionaryAlgorithm[PopMember](100)
print(evolution.population)
可以在此处的实例中找到用于定义通用 class 的类型:self.__orig_class__.__args__[0]
.
对于 class 方法只需使用此 -> cls.__args__[0]
还有另一种可能性可以避免在序列化时出现问题 类(即使用 pickle)。
除了使用 Generic,您还可以执行以下操作:
from typing import Callable, Any
import random
from enum import Enum
from functools import wraps
class PopMember:
def __init__(self):
self.x = random.randint(0, 100)
def __repr__(self):
return "Pop({})".format(self.x)
class PapMember:
def __init__(self):
self.x = random.randint(0, 200)
def __repr__(self):
return "Pop({})".format(self.x)
def check_type(func: Callable) -> Callable:
"""Decorator to check that the child class has defined the POINT_TYPE member attribute."""
@wraps(func)
def wrapper(obj, *args, **kwargs) -> Any:
if not hasattr(obj, 'T'):
raise NotImplementedError(
"You can not instantiate an abstract class.")
return func(obj, *args, **kwargs)
return wrapper
class EvolutionaryAlgorithm:
@check_type
def __init__(self, populationSize: int) -> None:
self.__population = [self.T() for _ in range(populationSize)]
@classmethod
@check_type
def create(cls, populationSize: int):
"""Example of classmethod."""
# You can use T as cls.T
return cls(populationSize=populationSize)
@property
def population(self):
return self.__population
class EvolutionaryAlgorithmPopMember(EvolutionaryAlgorithm):
T = PopMember
class EvolutionaryAlgorithmPapMember(EvolutionaryAlgorithm):
T = PapMember
class EvolutionaryAlgorithmFactory(Enum):
POP_MEMBER = EvolutionaryAlgorithmPopMember
PAP_MEMBER = EvolutionaryAlgorithmPapMember
def __call__(self, *args, **kwargs) -> Any:
return self.value(*args, **kwargs)
def __str__(self) -> str:
return self.name
evolution = EvolutionaryAlgorithmFactory.POP_MEMBER(100)
print(evolution.population)
这将避免很多问题,而不是破解 python 内部。
这里的主要优点是您可以重用类方法函数。
作为一名 C++ 程序员,以下代码对我来说似乎很自然,但它并不 运行:
from typing import TypeVar, Generic, List, NewType
TPopMember = TypeVar('TPopMember')
Population = NewType('Population', List[TPopMember])
class EvolutionaryAlgorithm(Generic[TPopMember]):
def __init__(self, populationSize: int) -> None:
# The following raises TypeError: 'TypeVar' object is not callable
self.__population = Population([TPopMember() for _ in range(populationSize)])
显然 Python 无法实例化实际上是 TypeVars 的 类(TPopMember)。我只是想创建一个列表(人口),其中包含几个默认初始化(Python 中怎么说?)TPopMembers。我该怎么办?
我正在使用 Python 3.7.2.
您没有意识到类型提示是 提示。也就是说,根本不要认为它是一个类型。你不能实例化它们。
据我从您的评论中了解到,您的意图是执行 C++ 模板允许您执行的操作。所以这是我实现这一目标的方法:
from typing import TypeVar, Generic, List, NewType, Type
import random
class PopMember:
def __init__(self):
self.x = random.randint(0, 100)
def __repr__(self):
return "Pop({})".format(self.x)
TPopMember = TypeVar("TPopMember")
Population = NewType('Population', List[TPopMember])
class EvolutionaryAlgorithm(Generic[TPopMember]):
def __init__(self, member_class: Type[TPopMember], populationSize: int) -> None:
self.__population = Population([member_class() for _ in range(populationSize)])
def __repr__(self):
return "EA({})".format(self.__population)
x = EvolutionaryAlgorithm(PopMember, 5)
print(x)
输出:
EA([Pop(49), Pop(94), Pop(24), Pop(73), Pop(66)])
您必须了解的是,如果您从 Generic[T]
派生了 class,则在创建 class 时需要使用 T
一些方法。在我的示例中,我 创建一个虚拟对象并解析它的 class 并启动它。通常我不会这样写,我可以把 class 作为参数 传入 class 给构造函数来请求生成这种特定类型的项目,因为 class 本身与它的实例不同,也是一个 Python 对象。 (感谢 chepner 的建议)
您可以执行以下操作:
from typing import TypeVar, Generic, List, NewType
import random
class PopMember:
def __init__(self):
self.x = random.randint(0, 100)
def __repr__(self):
return "Pop({})".format(self.x)
TPopMember = TypeVar('TPopMember')
Population = NewType('Population', List[TPopMember])
class EvolutionaryAlgorithm(Generic[TPopMember]):
def __init__(self, populationSize: int) -> None:
obj = self.__orig_class__.__args__[0]
self.__population = Population([obj() for _ in range(populationSize)])
@property
def population(self):
return self.__population
evolution = EvolutionaryAlgorithm[PopMember](100)
print(evolution.population)
可以在此处的实例中找到用于定义通用 class 的类型:self.__orig_class__.__args__[0]
.
对于 class 方法只需使用此 -> cls.__args__[0]
还有另一种可能性可以避免在序列化时出现问题 类(即使用 pickle)。
除了使用 Generic,您还可以执行以下操作:
from typing import Callable, Any
import random
from enum import Enum
from functools import wraps
class PopMember:
def __init__(self):
self.x = random.randint(0, 100)
def __repr__(self):
return "Pop({})".format(self.x)
class PapMember:
def __init__(self):
self.x = random.randint(0, 200)
def __repr__(self):
return "Pop({})".format(self.x)
def check_type(func: Callable) -> Callable:
"""Decorator to check that the child class has defined the POINT_TYPE member attribute."""
@wraps(func)
def wrapper(obj, *args, **kwargs) -> Any:
if not hasattr(obj, 'T'):
raise NotImplementedError(
"You can not instantiate an abstract class.")
return func(obj, *args, **kwargs)
return wrapper
class EvolutionaryAlgorithm:
@check_type
def __init__(self, populationSize: int) -> None:
self.__population = [self.T() for _ in range(populationSize)]
@classmethod
@check_type
def create(cls, populationSize: int):
"""Example of classmethod."""
# You can use T as cls.T
return cls(populationSize=populationSize)
@property
def population(self):
return self.__population
class EvolutionaryAlgorithmPopMember(EvolutionaryAlgorithm):
T = PopMember
class EvolutionaryAlgorithmPapMember(EvolutionaryAlgorithm):
T = PapMember
class EvolutionaryAlgorithmFactory(Enum):
POP_MEMBER = EvolutionaryAlgorithmPopMember
PAP_MEMBER = EvolutionaryAlgorithmPapMember
def __call__(self, *args, **kwargs) -> Any:
return self.value(*args, **kwargs)
def __str__(self) -> str:
return self.name
evolution = EvolutionaryAlgorithmFactory.POP_MEMBER(100)
print(evolution.population)
这将避免很多问题,而不是破解 python 内部。
这里的主要优点是您可以重用类方法函数。