2013-10-09 64 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一個實例,如果你加上參數都將失敗。

相關問題