Si utilizza una versione precedente di Python; il messaggio di errore è stato poi aggiornato:
>>> object.__new__(testclass1, 56)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object() takes no parameters
Python si lamenterà solo circa __init__
argomenti che non supportano se né __new__
né __init__
sono stati sovrascritti; per esempio. quando si ereditano entrambi da object
. testclass1
adatta tal caso, testclass3
non lo fa perché ha un metodo __init__
.
Questo per sostenere l'attuazione tipi immutabili che non hanno un uso per __init__
(che sarebbe ereditato da object
in quel caso), e tipi mutabili, dove __new__
non dovrebbe preoccuparsi quali argomenti __init__
aspetta (che di solito sarebbe più argomenti).
Vedi issue 1683368 dove Guido van Rossum, spiega le sue motivazioni per questo.
Il typeobject.c
source code ha questo da dire:
Vi chiederete perché object.__new__()
lamenta solo di argomenti
quando object.__init__()
sia di rango, e viceversa.
Considerate i casi d'uso:
Quando non viene sovrascritto, vogliamo sentire lamentele su eccesso (cioè, eventuali) argomenti, in quanto la loro presenza potrebbe indicare c'è un bug.
Quando si definisce un tipo immutabile, è probabile che l'override solo __new__()
, dal momento che __init__()
è chiamato troppo tardi per inizializzare un oggetto immutabile . Dal momento che __new__()
definisce la firma per il tipo , sarebbe un dolore di dover ignorare __init__()
solo per impedire che lamentano argomenti in eccesso.
Quando si definisce un tipo Mutabile, è probabile che si verifichi l'override solo __init__()
. Quindi qui si applica il ragionamento inverso: non dobbiamo voler sostituire il __new__()
solo per fermarlo dal lamentarsi.
Quando __init__()
viene sostituita, e la sottoclasse __init__()
chiama object.__init__()
, quest'ultimo deve lamentare eccesso argomenti; idem per __new__()
.
Utilizzare casi 2 e 3 rendono poco attraente per controllare incondizionatamente per argomenti in eccesso. La soluzione migliore che si rivolge a tutti i casi quattro d'uso è la seguente: __init__()
lamenta argomenti in eccesso meno __new__()
viene ignorata e __init__()
sia di rango (IOW, se __init__()
viene sostituita o __new__()
sia di rango); simmetricamente, __new__()
lamenta argomenti in eccesso a meno __init__()
viene sostituita e __new__()
sia di rango (IOW, se __new__()
viene sostituita o __init__()
sia di rango).
Tuttavia, per la compatibilità con le versioni precedenti, ciò causa un numero eccessivo di codice. Pertanto, in 2.6, si invierà sugli argomenti in eccesso quando vengono sovrascritti entrambi i metodi ; per tutti gli altri casi utilizzeremo le precedenti regole .
Nota che il metodo .__init__()
stesso sarà ancora lamentare! Quando si crea un'istanza, vengono chiamati sia __new__
sia __init__
; il tuo codice chiama solo __new__
direttamente e fa non invoca __init__
! La creazione di un'istanza di testclass1
e testclass3
entrambi non riesce se si passa in argomenti:
>>> 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)
L'unica differenza è che per testclass1
sono i metodi predefiniti per object()
che si lamentano invece un errore specifico per il costume __init__
.
Hai letto [questo] (http://hg.python.org/cpython/file/44ed0cd3dc6d/Objects/typeobject.c#l2818) un commento sui sorgenti python? Hanno deciso di * non * sollevare un errore in alcune circostanze per consentire di definire solo uno tra '__init__' o' __new__'. Altrimenti dovresti sempre ridefinirli, anche se non erano operativi. – Bakuriu
Non capisco che: s ho definito solo __init__, non ci sono argomenti (oltre al self ovviamente), sto passando un argomento a __new__, perché non genera un errore? – ychaouche