为什么或者更确切地说对象.__ new__在这两种情况下的工作方式不同

时间:2013-09-08 05:58:19

标签: python object constructor

Python版:“'2.7.3(默认,2013年4月10日,06:20:15)\ n [GCC 4.6.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>

更有趣!与上面的testclass1的结果进行比较。

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

我的问题是 (不是为什么)object__new__在这两种情况下表现不同? 另请注意,在第一种情况下,错误有点误导,因为在第二种情况下,object.__new__最终会引发争论!。

3 个答案:

答案 0 :(得分:5)

object.__new__object.__init__都经过精心构造的迷宫条件,在某些情况下允许过多的论据,在其他情况下引发错误,并在非常具体的情况下发出警告。 The code that implements the checks很容易遵循,但如果没有this elucidating comment,其背后的推理可能仍然难以理解:

  

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

     

考虑用例:

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

  2.   
  3. 定义不可变类型时,我们可能只覆盖__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中,我们将警告关于多余的参数   方法被覆盖;对于所有其他情况,我们将使用上述规则。

答案 1 :(得分:3)

您正在创建的的成员__init__()new()调用以处理任何创建参数,但在第一种情况下,您没有__init__所以无法传递任何参数。

答案 2 :(得分:3)

__new__静态方法将类作为其第一个参数。其他参数将传递给该类的__init__方法。由于您的班级没有__init__方法,__new__将不接受其他参数。

请查看the documentation了解详情。

至于“how”,它是用C(Objects/typeobject.c)实现的,但你可以用纯Python执行相同的检查:

def __new__(cls, *args, **kwargs):
    ...

    if not hasattr(cls, '__init__') and (args or kwargs):
        raise TypeError("object.__init__() takes no parameters")

    ...