为什么object .__ new__在这三种情况下的工作方式不同

时间:2013-10-09 16:18:05

标签: python object types constructor

来自问题Why does or rather how does object.__new__ work differently in these two cases

作者对原因不感兴趣,而是对如何感兴趣。

我非常想了解原因,特别是:

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

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

  3. >>> 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>
    

1 个答案:

答案 0 :(得分:15)

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

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

如果__init____new__都没有被覆盖,Python只会抱怨__init__不支持参数;例如当你从object继承时。 testclass1符合这种情况,testclass3没有,因为它有__init__方法。

这是为了支持实现不能用于__init__的不可变类型(在这种情况下将从object继承),可变类型,其中__new__不应该关注__init__期望的参数(通常是 more 参数)。

issue 1683368 Guido van Rossum解释他的动机。

typeobject.c source code有这样说:

  

你可能想知道为什么object.__new__()只抱怨论据   当object.__init__()未被覆盖时,反之亦然。

     

考虑用例:

     
      
  1. 当两者都没有被覆盖时,我们希望听到有关的投诉     超出(即任何)论据,因为他们的存在可以     表明存在错误。

  2.   
  3. 定义Immutable类型时,我们可能只会覆盖     __new__(),因为调用__init__()太晚无法初始化     不可改变的对象。由于__new__()定义了签名     类型,必须覆盖__init__()只是为了痛苦     阻止它抱怨过多的争论。

  4.   
  5. 定义Mutable类型时,我们可能只覆盖     __init__()。所以这里反过来的推理适用:我们没有     想要覆盖__new__()只是为了阻止它     侵犯。

  6.   
  7. 覆盖__init__()时,子类__init__()会调用     object.__init__(),后者应该抱怨过剩     参数;同上__new__()

  8.         

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

         

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

请注意,.__init__()方法本身仍会抱怨!创建实例时,会调用__new____init__;您的代码只会直接调用__new__并且调用__init__!如果传入参数,则创建testclass1testclass3的实例都会失败:

>>> 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)

唯一的区别是,对于testclass1object()的默认方法是投诉自定义__init__的特定错误。