2014-07-01 17 views
7

Perché il seguente codice funzionano bene in Python 2.x e non in Python 3.3+:Perché object .__ new__ con argomenti funziona bene in Python 2.xe non in Python 3.3+?

class TestA(object): 
    def __new__(cls, e): 
     return super(TestA, cls).__new__(TestB, e) 

class TestB(TestA): 
    def __init__(self, e): 
     print(self, e) 

TestA(1) 

Python 2.7.6 uscita:

(<__main__.TestB object at 0x7f6303378ad0>, 1) 

Python 3.1.5 uscita:

__main__:3: DeprecationWarning: object.__new__() takes no parameters 
<__main__.TestB object at 0x7f2f69db8f10> 1 

Python 3.2.3 e 3.2.5 di uscita:

<__main__.TestB object at 0xcda690> 1 

Python 3.3.5 e 3.4.1 di uscita:

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

Correlato: [Perché oggetto. \ _ \ _ Nuovo \ _ \ _ funziona in modo diverso in questi tre casi] (http://stackoverflow.com/q/19277399) –

+0

È l'output dell'interprete, prima stampa, secondo oggetto. Se eseguito come programma sarà una linea. Fisso. – tbicr

+0

Sei sicuro? Questo codice funziona su Python 2.7.4 e Python 3.2.3. –

risposta

3

object.__new__ ha sempre ignorato argomenti extra, ed è emesso un DeprecationWarning almeno dal Python 2.6.

Il motivo per cui non si vede lo DeprecationWarning in 2.7 e 3.2 è che dal 2.7 e 3.2 DeprecationWarning è stato suppressed by default; se usi python -Wd o PYTHONWARNINGS=default allora vedrai l'avviso.

In Python 3.3 DeprecationWarning è stato convertito in errore.

Il modo corretto di scrivere il codice (in qualsiasi versione di Python) è di inghiottire l'argomento in più in TestA.__new__:

class TestA(object): 
    def __new__(cls, e): 
     return super(TestA, cls).__new__(TestB) 

Dal TestB è derivato dal TestA, l'argomento extra will be passed to TestB.__init__.

0

È possibile spostare la funzione __init__ per TestA in questo modo:

class TestA(object): 
    def __new__(cls, e): 
     return super(TestA, cls).__new__(TestA) 

    def __init__(self, e): 
     print(self, e) 

TestA(1) 

Si noti come non è necessario TestB.

Nota come il parametro 'e' viene omesso dalla chiamata all'oggetto .__ nuovo__. La nuova funzione di classe oggetto accetta solo una classe come parametro e qualsiasi parametro aggiuntivo nella funzione __new__ sovraccaricata (in questo caso quella della classe TestA) viene automaticamente passato alla funzione di costruzione (__init__) della classe passata all'oggetto .__ new__ (che in questo caso è anche TestA).

Problemi correlati