我正在尝试使用新的python数据类来创建一些混合类(在我写这篇文章时,我认为这听起来像是一个鲁莽的想法),但我遇到了一些问题。请看下面的例子:
从数据类导入数据类
@dataclass
class NamedObj:
name: str
def __post_init__(self):
print("NamedObj __post_init__")
self.name = "Name: " + self.name
@dataclass
class NumberedObj:
number: int = 0
def __post_init__(self):
print("NumberedObj __post_init__")
self.number += 1
@dataclass
class NamedAndNumbered(NumberedObj, NamedObj):
def __post_init__(self):
super().__post_init__()
print("NamedAndNumbered __post_init__")
如果我尝试:
nandn = NamedAndNumbered('n_and_n')
print(nandn.name)
print(nandn.number)
我明白了
NumberedObj __post_init__
NamedAndNumbered __post_init__
n_and_n
1
建议它已为NamedObj
运行__post_init__
,但未为NumberedObj
运行。
我想要的是为它的混合类命名并编号运行__post_init__
。有人可能会认为,如果NamedAndNumbered
有这样一个__post_init__
就可以做到:
def __post_init__(self):
super(NamedObj, self).__post_init__()
super(NumberedObj, self).__post_init__()
print("NamedAndNumbered __post_init__")
但是当我试图调用NamedObj.__post_init__()
时,这只会给我一个错误AttributeError: 'super' object has no attribute '__post_init__'
此时,我不完全确定这是数据类的bug/特性,还是与我对Python继承方法的理解可能存在缺陷有关。谁能帮帮忙吗
这:
不会做你认为它会做的事
super(cls, obj)
将在type(obj).__mro__
中的cls
之后返回类的代理-因此,在您的情况下,将返回到object
。合作super()
调用的全部要点是避免显式地调用每一个家长协作
super()
调用的工作方式是,好的,通过“协作”-IOW,mro中的每个人都应该将调用转发到下一个类(实际上,super
名称是一个相当令人伤心的选择,因为它不是关于调用“超级类”,而是关于“调用mro中的下一个类”)注意,您希望每个“可组合”数据类(不是mixin-mixin只具有行为)中继调用,因此您可以按任意顺序组合它们。第一个简单的实现如下所示:
但是这不起作用,因为对于mro中的最后一个类(这里是
NamedObj
),mro中的下一个类是内置的object
类,它没有__post_init__
方法。解决方案很简单:只需添加一个将此方法定义为noop的基类,并使您的所有可组合数据类都从中继承:问题(很可能)与
dataclass
无关。问题在于Python的method resolution。在super()
上调用方法调用MRO链中父类中找到的第一个方法。因此,要使其正常工作,您需要手动调用父类的方法:另一种方法(如果您真的喜欢
super()
)是通过在所有父类中调用super()
来继续MRO链(但它需要在链中有一个__post_init__
):在这两种方法中:
相关问题 更多 >
编程相关推荐