2013-10-09 6 views
7

von Why does or rather how does object.__new__ work differently in these two cases Frage ObjektWarum .__ new__ funktioniert anders in diesen drei Fällen

der Autor nicht daran interessiert, das war, warum, sondern in der, wie.

Ich möchte sehr viel verstehen, warum, vor allem:

  1. warum ist nicht object.__init__ keine Parameter statt object.__new__ (in testclass1)

  2. gedruckt nimmt, warum kein Fehler für testclass3 erhoben wird? (Da es keine Argumente anders als selbst nimmt)

Code

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

Haben Sie [this] (http://hg.python.org/cpython/file/44ed0cd3dc6d/Objects/typeobject.c#l2818) Kommentar zu den Python-Quellen gelesen? Sie haben beschlossen, unter bestimmten Umständen * keinen * Fehler zu melden, um nur eines von "__init__" oder "__new__" zu definieren. Andernfalls müssten Sie sie immer neu definieren, selbst wenn es sich um No-Ops handelt. – Bakuriu

+1

Ich verstehe das nicht: s Ich definierte nur __init__, es braucht keine Argumente (außer offensichtlich selbst), ich übergebe ein Argument an __new__, warum löst es keinen Fehler aus? – ychaouche

Antwort

14

Sie verwenden eine ältere Version Python; die Fehlermeldung aktualisiert, da wurde:

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

Python nur über __init__ nicht unterstützen Argumente beschweren, wenn weder __new__ noch __init__ außer Kraft gesetzt worden ist; z.B. wenn Sie beide von object erben. testclass1 passt für diesen Fall, nicht, weil es eine __init__ Methode hat.

Dies ist unveränderlich Typen zu unterstützen Implementierung, die für __init__ keine Verwendung haben (die von object in diesem Fall vererbt werden würde), und änderbare Typen, wo __new__ sollte über, welche Argumente __init__ erwartet nicht kümmern (die normalerweise wäre mehr Argumente).

Siehe issue 1683368 wo Guido van Rossum seine Motivation dafür erklärt.

Die typeobject.c source code hat folgendes zu sagen:

Sie fragen sich vielleicht, warum nur object.__new__() über Argumente klagt
wenn object.__init__() nicht außer Kraft gesetzt wird, und umgekehrt.

Betrachten Sie die Anwendungsfälle:

  1. Wenn weder außer Kraft gesetzt wird, möchten wir Beschwerden über Überschuss (das heißt, irgend) Argumente hören, da ihre Anwesenheit könnte zeigen es einen Fehler gibt.

  2. Wenn ein unveränderlichen Typen definiert, werden wir wahrscheinlich nur __new__(), außer Kraft zu setzen, da __init__() zu spät genannt wird, ein unveränderliches Objekt zu initialisieren. Da __new__() die Signatur für den Typ definiert, wäre es ein Schmerz, __init__() nur zu außer Kraft zu setzen, damit es sich über übermäßige Argumente beschwert.

  3. Beim Definieren eines änderbaren Typs überschreiben wir wahrscheinlich nur __init__(). Also hier gilt die umgekehrte Argumentation: Wir wollen __new__() nicht überschreiben wollen, nur um es von zu beklagen.

  4. Wenn __init__() außer Kraft gesetzt wird, und die Unterklasse __init__() object.__init__() nennt, sollte dieser über überschüssige Argumente zu beklagen; dito für __new__().

Anwendungsfälle 2 und 3 machen es unattraktiv für Überschuss Argumente bedingungslos zu überprüfen. Die beste Lösung, die alle vier Verwendung Fällen richtet sich wie folgt: __init__() beschwert sich über überschüssige Argumente es sei denn, __new__() wird außer Kraft gesetzt und __init__() nicht (IOW, wenn __init__() außer Kraft gesetzt wird oder __new__() nicht überschrieben) außer Kraft gesetzt; symmetrisch klagt über __new__() überschüssige Argumente, es sei denn __init__() außer Kraft gesetzt wird, und ist nicht __new__() (IOW, wenn __new__() außer Kraft gesetzt wird, oder __init__() nicht überschrieben) außer Kraft gesetzt.

Aus Gründen der Abwärtskompatibilität bricht dies jedoch zu viel Code. Daher werden wir in 2.6 warnen über überschüssige Argumente, wenn beide Methoden überschrieben werden; Für alle anderen Fälle verwenden wir die obigen Regeln.

Beachten Sie, dass die .__init__() Methode selbst wird sich beschweren, immer noch! Wenn Sie eine Instanz erstellen, werden sowohl __new__ als auch __init__ aufgerufen. Ihr Code ruft nur __new__ direkt und macht nicht aufrufen __init__! Erstellen einer Instanz von testclass1 und testclass3 beide schlägt fehl, wenn Sie in Argumente übergeben:

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

Der einzige Unterschied besteht darin, dass für testclass1 es die Standardmethoden für object(), die für die benutzerdefinierte __init__ stattdessen einen bestimmten Fehler beklagen ist.

Verwandte Themen