python-3.x 示例化属于TypeVar的类型

velaa5lx  于 2023-01-27  发布在  Python
关注(0)|答案(4)|浏览(145)

作为一个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不能示例化类(TPopMember),这些类实际上是TypeVars。我只想创建一个列表(Population),其中包含两个默认初始化的(Python中怎么说?)TPopMember。我应该怎么做呢?
我用的是Python 3.7.2。

2izufjch

2izufjch1#

你没有意识到类型提示是一个提示。换句话说,不要认为它是一个类型。你不能示例化它们。
我从你的评论中了解到,你的意图是做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]派生了一个类,你需要在创建类的时候使用T。在我的例子中,我创建了一个伪对象,解析它的类并初始化它。通常我不会这样写。我可以直接把类作为参数传递给构造函数来请求生成这个特定类型的项因为类本身,不同于它的示例,也是Python对象(感谢chepner的建议)

wxclj1h5

wxclj1h52#

您可以执行以下操作:

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)

用于定义泛型类的类型可以在下面的示例中找到:* * 一月一日**
对于类方法,只需使用-〉cls.__args__[0]

hgqdbh6s

hgqdbh6s3#

还有另一种可能性可以避免序列化类时出现的问题(即使用pickle)。
您可以执行以下操作,而不使用“通用”:

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内部。
这里的主要优点是可以重用classmethod函数。

pw136qt2

pw136qt24#

更简单的解决方案是在 enum 工厂中使用 functools.partial

import random
from typing import Any
from enum import Enum
from functools import partial

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 "Pap({})".format(self.x)

class EvolutionaryAlgorithm:
    def __init__(self, member_type: Any, populationSize: int) -> None:
        self.__member_type = member_type
        self.__population = [self.__member_type() for _ in  range(populationSize)]

    @property
    def population(self):
        return self.__population

class EvolutionaryAlgorithmFactory(Enum):
    POP_MEMBER = partial(EvolutionaryAlgorithm, PopMember)
    PAP_MEMBER = partial(EvolutionaryAlgorithm, PapMember)

    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)

相关问题