2013-10-07 9 views
10

TL; DR Come scoprire se una funzione è stata definita utilizzando @classmethod o qualcosa con lo stesso effetto?Verificare se una funzione utilizza @classmethod


mio problema

Per attuare un decoratore classe desidero controllare se un metodo prende la classe come primo parametro, ad esempio come ottenuto tramite

@classmethod 
def function(cls, ...): 

ho trovato una soluzione per verificare @staticmethod tramite il modulo types (isinstance(foo, types.UnboundMethodType) è False se lo foo è statico, vedere here), Ma non ha trovato nulla su come farlo per @classmethod


Contesto

Quello che sto cercando di fare è qualcosa sulla falsariga di

def class_decorator(cls): 
    for member in cls.__dict__: 
     if (isclassmethod(getattr(cls, member))): 
      # do something with the method 
      setattr(cls, member, modified_method) 
    return cls 

e lo faccio non so come implementare quello che ho chiamato isclassmethod in questo esempio

risposta

15

Per Python 2, è necessario verificare sia se l'oggetto è un metodo, e se __self__ punti per la classe (per i metodi regolari sarà None quando viene recuperato dal classe):

>>> class Foo(object): 
...  @classmethod 
...  def bar(cls): 
...   pass 
...  def baz(self): 
...   pass 
... 
>>> Foo.baz 
<unbound method Foo.baz> 
>>> Foo.baz.__self__ 
>>> Foo.baz.__self__ is None 
True 
>>> Foo.bar.__self__ 
<class '__main__.Foo'> 
>>> Foo.bar.__self__ is Foo 
True 

In Python 3, metodi regolari mostrano come funzioni (metodi non legato sono state abolite).

Combinare questo con inspect.ismethod() per un metodo fail-safe per rilevare un metodo di classe sia Python 2 e 3:

import inspect 

if inspect.ismethod(cls.method) and cls.method.__self__ is cls: 
    # class method 

L'attributo method.__self__ stata aggiunta in Python 2.6 per coerenza con Python 3. In Python 2.6 e 2.7 è un alias di method.im_self.

5

È necessario utilizzare inspect.ismethod. Funziona perché classmethod lega la funzione all'oggetto classe. Vedere il seguente codice:

>>> class Foo: 
...  @classmethod 
...  def bar(): 
...    pass 
...  def baz(): 
...    pass 
... 
>>> Foo.bar 
<bound method type.bar of <class '__main__.Foo'>> 
>>> Foo.baz 
<function Foo.baz at 0x0000000002CCC1E0> 
>>> type(Foo.bar) 
<class 'method'> 
>>> type(Foo.baz) 
<class 'function'> 
>>> import inspect 
>>> inspect.ismethod(Foo.bar) 
True 
>>> inspect.ismethod(Foo.baz) 
False 
+5

Questo vale solo per Python 3 –

+1

C'è qualcosa che funziona sia per Python 2 che per Python 3 (personalmente, utilizzo 2.7) – hlt

2
class Foo(object): 
    @classmethod 
    def baaz(cls): 
     print "baaz" 

isinstance(Foo.__dict__["baaz"], classmethod) 
0

questo funziona per me:

def is_classmethod(method): 
    """ 
    Is method a classmethod? 
    """ 
    return isinstance(getattr(method, '__self__', None), type) 

mette alla prova in fondo se method.__self__ esiste ed è un classe, come nella risposta di Martijn, ma non richiede l'accesso alla classe stessa.

Problemi correlati