从 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
.
的_tp
class属性中
使用此代码,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 的名称。
我有一个 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
.
_tp
class属性中
使用此代码,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 的名称。