从 class 工厂制造 parent class return child

Make parent class return a child from class factory

我有一个 parent class,我想制作它以便我可以 return 它的 children 来自 class 工厂,这里是一些代码:

class Super:
    def __new__(cls, t):
        return class_factory(t)

# Because I need a Super class with some custom state
def class_factory(t):
    class Sub(Super):
        t = t

        def __init__(self):
            pass

    return Sub

assert isinstance(Super(1)(), Super)

我收到以下错误:

TypeError: __new__() missing 1 required positional argument: 't'

我知道它正在尝试调用 Super__new__ 方法。有没有办法跳过它,或者至少以不会导致无限递归的方式保留类型签名? (我 需要 来保留两个 class 的类型签名)。

这可能有效:

class Super:
    def __new__(cls, t):
        return class_factory(t)

def class_factory(t):
    class Sub(Super):
        _tp = t
        def __new__(cls, *args, **kwargs):
            instance = object.__new__(cls)
            return instance

        def __init__(self, *args, **kwargs):
            pass

    return Sub

为避免错误,您需要在 Sub 中定义自定义 __new__() 方法,这样您就可以避免递归调用 Super__ new__() 方法。
类型保存在Sub.

_tpclass属性中

使用此代码,assert isinstance(Super(1)(), Super) 不会引发任何错误。

评论后编辑

已修复 *args**kwargs。规则是 Sub.__init__() 中的任何参数签名也必须由 Sub.__new__() 使用。例如,如果你需要 Sub.__init__(self, a, b) 那么你应该有 Sub.__new__(cls, a, b).

当我 运行 你的代码时,我得到了一个不同的错误,即:

NameError: name 't' is not defined

t = t 行。

这是因为 class 语句的主体是在它自己的命名空间中执行的,因此封闭命名空间中的 t 不像通常那样在范围内。另一个问题是你的 __new__() 没有调用它的基数 class' __new__().

最后,对Super(1)()的调用是错误的。调用 class returns class 的实例(或者在本例中,调用 subclass 的实例)。

要解决所有这些问题并让您的代码正常工作,您可能需要这样做:

class Super:
    def __new__(cls, t):
        subclass = class_factory(t)   # Create subclass.
        return super().__new__(subclass)  # Using base class method to avoid recursion.


def class_factory(t_arg):
    class Sub(Super):
        t = t_arg

        def __init__(self, t):
            pass

    return Sub

# Note Super(1) returns an instance of the subclass.
assert isinstance(Super(1), Super)

更新:

根据您的意见,我建议改用 class 装饰器。 — 像这样:

def inject(name, value):

    def decorator(cls):
        setattr(cls, name, value)
        return cls

    return decorator


@inject('t', 42)
class Test:
    def __init__(self):
        print(self.t)


assert isinstance(Test(), Test)  # -> 42

这不会创建子classes,但是您可以根据需要更改修饰的 class 的名称。