2013-10-09 264 views
7

从问题Why does or rather how does object.__new__ work differently in these two cases为什么在这三种情况下

笔者是不感兴趣的原因,而是在如何不同对象.__ new__工作。

我就非常想知道为什么,特别是:

  1. 为什么不是object.__init__不带印刷的,而不是object.__new__ (in testclass1)

  2. 参数,为什么不会引发错误的testclass3? (因为它没有超越自我其他参数)

代码

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

你读过[this](http://hg.python.org/cpython/file/44ed0cd3dc6d/Objects/typeobject.c#l2818)对Python源代码的评论吗?他们决定在某些情况下不会提出错误,只允许定义一个'__init__'或'__new__'。否则,即使它们没有运行,你也必须重新定义它们。 – Bakuriu

+1

我不明白:我只定义__init__,它不需要任何参数(除了明显的自我),我传递给__new__的参数,为什么它不会引发错误? – ychaouche

回答

14

您使用的是旧版本的Python;错误信息进行了更新:

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

如果既不__new__也不__init__已经重写了Python将只抱怨__init__不支持的论点;例如当你从object继承。 testclass1适合这种情况,testclass3并不是因为它有一个__init__方法。

这是支持实施不具有__init__一个使用(这会从object在这种情况下被继承)不变类型,可变类型,其中__new__不应该关心什么样的参数__init__预期(这通常会是更多参数)。

请参阅issue 1683368其中Guido van Rossum解释了他对此的动机。

typeobject.c source code有这样一段话:

你也许会奇怪,为什么只object.__new__()抱怨争论
object.__init__()不被覆盖,反之亦然。

考虑用例:

  1. 当既没有被覆盖,我们想听到的抱怨 过量(即任意)的参数,因为它们的存在可能 表明有一个错误。

  2. 当定义一个不可变的类型,我们可能只覆盖 __new__(),因为__init__()被称为来不及初始化 不可变对象。由于__new__()定义了 类型的签名,因此不得不重写__init__(),直到 停止抱怨过多的参数。

  3. 定义可变类型时,我们很可能只覆盖 __init__()。所以这里的反驳推理适用:我们不要 想要覆盖__new__()只是为了阻止它从 抱怨。

  4. __init__()被覆盖,并且__init__()调用 object.__init__()子类,后者应抱怨过量 参数;同上__new__()

用例2和3使其吸引力无条件地检查 多余的参数。这解决了所有4所用 情况下,最好的解决方法如下:__init__()抱怨过多的争论 除非__new__()无效,__init__()不被覆盖 (IOW,如果__init__()被重写或__new__()未覆盖); 对称,__new__()抱怨过量参数除非 __init__()无效,__new__()不重写 (IOW,如果__new__()被重写或__init__()未覆盖)。

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

注意,.__init__()方法本身仍然会抱怨!在创建实例时,调用__new____init__;你的代码只能直接调用__new__,并且不是调用__init__

>>> 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()是抱怨,而不是一个特定的错误自定义__init__默认的方法:创建testclass1testclass3一个实例,如果你加上参数都将失败。

相关问题