2013-10-07 8 views
10

TL; DR Wie finde ich heraus, ob eine Funktion mit @classmethod oder etwas mit dem gleichen Effekt definiert wurde?Überprüfen Sie, ob eine Funktion @classmethod verwendet


Mein Problem

Für eine Klasse Dekorateur Umsetzung würde ich prüfen möchte, ob eine Methode, um die Klasse als erstes Argument nimmt, zum Beispiel erreicht, wie sie über

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

gefunden Eine Lösung zur Überprüfung auf @staticmethod über das Modul types (isinstance(foo, types.UnboundMethodType) ist False, wenn die foo statisch ist, siehe here), Aber nichts finden, wie man nicht für @classmethod so tun


Kontext

Was ich versuche, etwas entlang der Linien von

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 

zu tun ist, und ich tun nicht wissen, wie man das implementiert, was ich in diesem Beispiel isclassmethod nannte

Antwort

15

Für Python 2, müssen Sie beide testen, ob das Objekt eine Methode ist, und wenn __self__ Punkte der Klasse (für normale Methoden werden es None sein, wenn sie von der abgerufene Klasse):

>>> 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, zeigen regelmäßige Methoden als Funktionen up (ungebundene Methoden wurden beseitigt).

Kombinieren Sie dies mit inspect.ismethod() für eine ausfallsichere Methode sowohl eine Klassenmethode in Python zu erkennen, 2 und 3:

import inspect 

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

Das method.__self__ Attribut wurde in Python 2.6 hinzugefügt, um im Einklang mit Python 3. In Python 2.6 und 2.7 ist ein Alias ​​von method.im_self.

5

Sie solltenverwenden. Es funktioniert, weil die Klassenmethode die Funktion an das Klassenobjekt bindet. Siehe den folgenden Code:

>>> 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

Dies gilt nur für Python 3 –

+1

Gibt es etwas für Python 2 und Python 3 (persönlich benutze ich 2,7) – hlt

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

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

Dies funktioniert für mich:

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

Es prüft im Grunde, wenn method.__self__ existiert und ist eine Klasse, wie in Martijn Antwort, benötigen aber keinen Zugriff auf die Klasse selbst.