2012-01-19 13 views
5

Come si può rendere statico un metodo di classe dopo che la classe è stata definita? In altre parole, perché il terzo caso fallisce?Creare un metodo statico da un metodo esistente al di fuori della classe? (errore "metodo non associato")

 

>>> class b: 
... @staticmethod 
... def foo(): 
... pass 
... 
>>> b.foo() 
>>> class c: 
... def foo(): 
... pass 
... foo = staticmethod(foo) 
... 
>>> c.foo() 
>>> class d: 
... def foo(): 
... pass 
... 
>>> d.foo = staticmethod(d.foo) 
>>> d.foo() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unbound method foo() must be called with d instance as first argument (got nothing instead) 

risposta

6

Dopo la classe è definita, foo è un oggetto non associato metodo (un involucro che lega la funzione alla classe), non una funzione. Il wrapper proverà a passare un'istanza della classe (self) alla funzione come primo argomento e quindi si lamenta che non ne è stata data una.

staticmethod() deve essere utilizzato solo con le funzioni. Mentre la classe è ancora in fase di definizione (come nel tuo b e c) foo() è ancora una funzione, poiché il wrapper del metodo viene applicato quando la definizione della classe è completa.

È possibile estrarre la funzione dall'oggetto metodo non associato, applicare staticmethod() e assegnarlo alla classe.

In Python 3 non sono disponibili metodi di istanza non associati (i metodi memorizzati sulle classi sono funzioni semplici). Così il vostro codice originale sarebbe in realtà lavorare bene su Python 3.

un modo che funziona sia su Python 2 e Python 3 è:

d.foo = staticmethod(d.__dict__['foo']) 

(evita anche la creazione e scartando il metodo involucro.)

+0

Non dovrebbe essere 'd.foo.im_func'? –

+0

Sì, grazie. Fisso! – kindall

+0

Bene, è necessario contrassegnarli con 'staticmethod' per chiamarli in modo equivalente su istanze, non solo sulla classe stessa. 'd.foo()' funziona con o senza il wrapping 'staticmethod', ma' d(). foo() 'esploderebbe (proverebbe a passare' self' che 'foo' non accetta). Certo, non esiste alcuna funzionalità relativa all'istanza che richiederebbe di chiamarli su un'istanza, ma per DRY, i metodi che fanno riferimento al metodo statico possono e dovrebbero chiamarlo 'self.foo()' invece di nominare esplicitamente la classe. – ShadowRanger

5

È necessario passare la funzione, non il metodo non associato.

>>> class d: 
... def foo(): 
...  pass 
... 
>>> d.foo = staticmethod(d.foo.im_func) 
>>> d.foo() 
Problemi correlati