2012-02-01 8 views
31

Il Changelog per Python 2.2 (in cui sono state introdotte classi di nuovo stile) dice quanto segue sulla funzione __new__:Perché non __new__ in Python le classi new-style sono un metodo di classe?

__new__ è un metodo statico, non è un metodo di classe. Inizialmente pensavo che avrebbe dovuto essere un metodo di classe, ed è per questo che ho aggiunto la primitiva classmethod. Sfortunatamente, con i metodi di classe, gli upcalls non funzionano proprio in questo caso, quindi ho dovuto renderlo un metodo statico con una classe esplicita come primo argomento.

Tuttavia, non posso pensare a metodi di classe perché non avrebbe funzionato per questo scopo, ed è certamente un aspetto migliore. Perché lo __new__ non è finito come metodo di classe alla fine? A cosa si riferisce Guido quando afferma che "in tal caso" i ritardi non funzionano in questo caso "?

risposta

17

__new__ essendo metodo statico consente a un caso d'uso quando si crea un'istanza di una sottoclasse in esso:

return super(<currentclass>, cls).__new__(subcls, *args, **kwargs) 

Se new è un metodo di classe allora quanto sopra è scritto come:

return super(<currentclass>, cls).new(*args, **kwargs) 

e non c'è posto per mettere subcls.

Non vedo davvero quando questo sarebbe un uso corretto di __new__, però. Forse non lo vedo, ma questo mi sembra un uso completamente patologico (e va detto che, se lo vuoi ancora davvero, allora puoi accedervi con object.__new__.__func__). Per lo meno, trovo molto difficile immaginare che sarebbe stato il motivo per Guido di cambiare __new__ da metodo di classe a metodo statico.

Un caso più comune sarebbe chiamare genitore __new__ senza utilizzare super(). You need a place to pass cls explicitly in this case:

class Base(object): 
    @classmethod 
    def new(cls): 
     print("Base.new(%r)" % (cls,)) 
     return cls() 

class UseSuper(Base): 
    @classmethod 
    def new(cls): 
     print("UseSuper.new(%r)" % (cls,)) 
     return super(UseSuper, cls).new() # passes cls as the first arg 

class NoSuper(Base): 
    @classmethod 
    def new(cls): 
     print("NoSuper.new(%r)" % (cls,)) 
     return Base.new() # passes Base as the first arg 

class UseFunc(Base): 
    @classmethod 
    def new(cls): 
     print("UseFunc.new(%r)" % (cls,)) 
     return Base.new.im_func(cls) # or `.__func__(cls)`. # passes cls as the first arg 

print(UseSuper.new()) 
print('-'*60) 
print(NoSuper.new()) 
print('-'*60) 
print(UseFunc.new()) 
+0

@Duncan: Ho volutamente usato 'new' piuttosto che' __new__'. Se non è chiaro, lascia un commento che cercherò di elaborare. – jfs

+0

Penso che se tu avessi usato un nome che era un po 'più distinto rispetto a far cadere i caratteri di sottolineatura, sarebbe stato più chiaro, ma ora capisco grazie. – Duncan

+0

Quando sarebbe effettivamente un problema, però? Se vuoi un'istanza di 'subcls', perché non dovresti chiamare' subcls.new() '? Farlo nel modo in cui descrivi ha l'effetto di non eseguire le funzioni '__new__' corrette su' subcls'. – Dolda2000

Problemi correlati