为啥 __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__ 在指向超类时表现不同?的主要内容,如果未能解决你的问题,请参考以下文章