我发现了问题,其中正在讨论使用
__post_init__
显式调用父级的super()
方法,但如果我尝试这样做:
from dataclasses import dataclass
@dataclass
class A:
def __post_init__(self):
print("A")
@dataclass
class B(A):
pass
b = B()
它将输出:
A
因此,父母方法无需显式调用即可工作。
__post_init__
数据类的方法不会被调用?正在讨论的问题是
__init__
和__post_init__
有何不同。
object
定义 __init__
;它不执行任何操作,但这意味着在您自己的 super().__init__
定义中调用 __init__
始终是安全的。您必须注意传递给它的参数,但属性查找本身总是会成功。
object
not 定义 __post_init__
,因此调用 super().__post_init__
需要您知道 MRO 中是否至少有一个类会定义它,或者您首先检查它,否则您将得到 AttributeError
.
因此,
__post_init__
,如果定义了,将总是被调用,但是对于显式的super().__post_init__
调用,假设该方法存在是不安全的。
默认情况下,
dataclass
装饰器会生成一个__init__
方法,该方法执行以下操作(除其他外):
self
的属性self.__post_init__
Python 的继承机制是这样的,如果父类有一个属性,子类就会继承它,除非另有说明。这就是重点。
要禁用继承,您必须以某种方式覆盖它。完全禁用继承方法的 Python 方法是在子类中将其设置为
None
:
@dataclass
class B(A):
__post_init__ = None
NotImplementedError
的文档中找到此技术,但您不应该在此处使用:
注意: [
] 不应该用于指示根本不支持某个运算符或方法 - 在这种情况下,要么保留运算符/方法未定义,要么如果是子类,则将其设置为NotImplementedError
。None
事实上,任何时候子类重写方法时,都不会调用父类的实现,除非明确告知这样做。
换句话说,将child的方法设置为
None
大致相当于
@dataclass
class B(A):
def __post_init__(self):
pass
将名称从子类中删除大致相当于
@dataclass
class B(A):
def __post_init__(self):
super().__post_init__()
通过不在子实现中调用
super().__post_init__()
,可以防止父实现被执行。