什么时候__post_init__方法不被调用?

问题描述 投票:0回答:2

我发现了问题,其中正在讨论使用

__post_init__
显式调用父级的
super()
方法,但如果我尝试这样做:

from dataclasses import dataclass


@dataclass
class A:
    def __post_init__(self):
        print("A")


@dataclass
class B(A):
    pass


b = B()

它将输出:

A

因此,父母方法无需显式调用即可工作。

  1. 我不明白这个问题到底讲了什么,或者继承问题解决了吗?
  2. 在哪种情况下
    __post_init__
    数据类的方法不会被调用?
python oop inheritance overriding python-dataclasses
2个回答
4
投票

正在讨论的问题是

__init__
__post_init__
有何不同。

object
定义
__init__
;它不执行任何操作,但这意味着在您自己的
super().__init__
定义中调用
__init__
始终是安全的。您必须注意传递给它的参数,但属性查找本身总是会成功。

object
not 定义
__post_init__
,因此调用
super().__post_init__
需要您知道 MRO 中是否至少有一个类会定义它,或者您首先检查它,否则您将得到
AttributeError 
.

因此,

__post_init__
,如果定义了,将总是被调用,但是对于显式的
super().__post_init__
调用,假设该方法存在是不安全的。


4
投票

默认情况下,

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__()
,可以防止父实现被执行。

© www.soinside.com 2019 - 2024. All rights reserved.