为啥 __new__ 和 __init__ 在指向超类时表现不同?

Posted

技术标签:

【中文标题】为啥 __new__ 和 __init__ 在指向超类时表现不同?【英文标题】:Why do __new__ and __init__ appear to behave differently when punting to a superclass?为什么 __new__ 和 __init__ 在指向超类时表现不同? 【发布时间】:2016-11-06 16:37:43 【问题描述】:

我在阅读元类here 时遇到了以下代码,尽管我不知道这种区别是否特定于元类,我怀疑它不是:

class MetaBase(type):
    def __new__(mcl, name, bases, nmspc):
        print('MetaBase.__new__\n')
        return super(MetaBase, mcl).__new__(mcl, name, bases, nmspc)

    def __init__(cls, name, bases, nmspc):
        print('MetaBase.__init__\n')
        super(MetaBase, cls).__init__(name, bases, nmspc)

请注意,super().__init__() 调用省略了第一个参数。我猜它是隐式传递的,因为它在 super() 返回的任何类上调用一个方法。这就是我经常看到构建此类调用的方式,尽管它们通常涉及普通类上的self,而不是元类上的 cls/mcl。

super().__new__() 调用显式传递了mcl。我不明白为什么。签名在我看来是一样的。

我很困惑。 super() 是否在每种情况下都返回不同的东西,也许?这里发生了什么,当我覆盖其他魔法方法时,我应该期望被这个咬吗?

[编辑:有人建议这是 this question 的副本,它描述了它们的不同功能。虽然在其中的一些示例中展示了相同的差异,但我没有看到任何说明它存在的原因或它是否是 __new__ 独有的。]

【问题讨论】:

__new__ 是一个静态方法。 __init__ 是一个实例方法。 Python's use of __new__ and __init__?的可能重复 关于编辑,__new__的官方文档第一句:“__new__() is a static method (special-cased so you need not declare it as such)” 好吧,这很有道理。在答案中解释一下,我会接受。不过,我还想知道是否还有其他神奇的静态方法需要担心——据我所知没有,但显然我不能相信没有标记为静态的东西实际上是非-静态的。 【参考方案1】:

super().__new__() 调用显式传递了 mcl。我不 明白为什么。签名在我看来是一样的。

__new__ 方法很奇怪,因为它是一个静态方法,但具有特殊情况,因此您不必这样声明它。作为一个静态方法意味着您必须显式传入任何需要的变量(在本例中为元类)。

相比之下,__init__ 与任何其他常规方法一样。当您从实例中查找它时,该实例会自动作为第一个参数传入。无论您是直接使用cls.__init__(name, bases, nmspc) 调用父级,还是使用带有super(MetaBase, cls).__init__(name, bases, nmspc)super(),这都有效。两者都将 cls 作为第一个参数传入。这就是绑定方法对普通类和元类的工作方式。 super() 使用与否都无所谓。

所以,一个奇怪的情况是__new__,因为它是一个staticmethod,根据定义它没有自动前置行为。

我是否应该期望在覆盖其他魔法时被这个咬伤? 方法?

静态方法比较少见。而在神奇的方法中,__new__是我唯一能想到的一种。所以,你应该是安全的:-)

【讨论】:

__new__ 不是类方法而不是静态方法吗?

以上是关于为啥 __new__ 和 __init__ 在指向超类时表现不同?的主要内容,如果未能解决你的问题,请参考以下文章

OC源码探索02:alloc、init和new的区别

python常见问题

\_\_init\_\_和\_\_new\_\_

__init__和__new__

__new__和__init__的区别

Python-__init__ 和 __new__区别和原理