7

来自问题为什么或者更确切地说 object.__new__ 在这两种情况下的工作方式不同

作者对为什么不感兴趣,而是对如何。

我非常想了解原因,尤其是:

  1. 为什么不object.__init__打印参数而不是object.__new__ (in testclass1)

  2. 为什么没有为 testclass3 引发错误?(因为它除了 self 不需要任何参数)

代码

>>> class testclass1(object):
    ...     pass
    ... 

>>> class testclass2(object):
    ...     def __init__(self,param):
    ...             pass
    ... 

>>> a = object.__new__(testclass1, 56)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: object.__new__() takes no parameters

>>> b = object.__new__(testclass2, 56)

>>> b
    <__main__.testclass2 object at 0x276a5d0>

>>> class testclass3(object):
    ...     def __init__(self):
    ...             pass
    ... 

>>> c = object.__new__(testclass3, 56)

>>> c
    <__main__.testclass3 object at 0x276a790>

>>> c1 = object.__new__(testclass3)

>>> c1
    <__main__.testclass3 object at 0x276a810>
4

1 回答 1

18

您使用的是较旧的 Python 版本;错误消息已更新:

>>> object.__new__(testclass1, 56)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object() takes no parameters

如果既没有也没有被覆盖,Python 只会抱怨__init__不支持参数;例如,当您从. 适合这种情况,不是因为它有方法。__new____init__objecttestclass1testclass3__init__

这是为了支持实现不使用 for 的不可变类型__init__(在这种情况下将继承自object可变类型,其中__new__不应该关心__init__期望的参数(通常是更多参数)。

请参阅issue 1683368,Guido van Rossum 解释了他的动机。

typeobject.c源代码有这样的说法:

你可能想知道为什么只有在没有被覆盖 时才object.__new__()抱怨参数,反之亦然。
object.__init__()

考虑用例:

  1. 当两者都没有被覆盖时,我们希望听到关于过多(即任何)参数的抱怨,因为它们的存在可能表明存在错误。

  2. 在定义 Immutable 类型时,我们可能只重写 __new__(),因为__init__()调用太晚而无法初始化 Immutable 对象。由于__new__()定义了类型的签名,因此必须重写__init__()只是为了阻止它抱怨过多的参数是很痛苦的。

  3. 在定义 Mutable 类型时,我们可能只覆盖 __init__(). 所以这里适用相反的推理:我们不想__new__()为了阻止它抱怨而重写。

  4. When__init__()被覆盖,子类__init__()调用 object.__init__(),后者应该抱怨过多的参数;同上__new__()

用例 2 和 3 使得无条件检查多余参数变得没有吸引力。解决所有四个用例的最佳解决方案如下:__init__()抱怨过多的参数,除非__new__()被覆盖__init__()且未被覆盖(IOW,如果__init__()被覆盖或__new__()未被覆盖);对称地,__new__()抱怨过多的参数,除非 __init__()被覆盖并且__new__()未被覆盖(IOW,如果__new__()被覆盖或__init__()未被覆盖)。

但是,为了向后兼容,这会破坏太多代码。因此,在 2.6 中,当两个方法都被覆盖时,我们会警告过多的参数;对于所有其他情况,我们将使用上述规则。

请注意,.__init__()方法本身仍然会抱怨!当你创建一个实例时,两者都会__new____init__调用;您的代码仅__new__直接调用而不调用__init__!如果传入参数,则创建testclass1and的实例都会失败:testclass3

>>> testclass1(56)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object() takes no parameters
>>> testclass3(56)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes exactly 1 argument (2 given)

唯一的区别是testclass1它是该object()抱怨的默认方法,而不是 custom 的特定错误__init__

于 2013-10-09T16:39:03.570 回答