2013-10-07 14 views
10

TL; DR如何查找是否使用@classmethod或者具有相同效果的函数来定义函数?检查一个函数是否使用@classmethod


我的问题

为了实现一类的装饰,我想检查是否有方法将类作为其第一个参数,例如通过

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

我找到了实现通过types模块检查@staticmethod的解决方案(isinstance(foo, types.UnboundMethodType)False,如果foo是静态的,请参阅here ),但并没有找到关于如何为@classmethod


语境

这样做的任何事情,我试图做的是沿着

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 

和我做的东西线不知道如何实施我在此示例中所称的isclassmethod

回答

15

对于Python 2,你需要测试这两个如果对象是一个方法,如果__self__指向类(常规方法从检索时它会None类):

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

在Python 3中,常规方法显示为函数(未绑定的方法已被删除)。与Python 3.

import inspect 

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

在Python 2.6的溶液中加入该method.__self__属性要一致在Python:

inspect.ismethod()结合这对于一个故障安全方法在两个Python 2和3来检测一个类的方法2.6和2.7是method.im_self的别名。

5

您应该使用inspect.ismethod。它的工作原理是因为classmethod将函数绑定到类对象。请看下面的代码:

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

这仅适用于Python 3 –

+1

对于Python 2和Python 3(对于个人而言,我使用2.7)都有效果吗? – hlt

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

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

这个工作对我来说:

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

它基本上检测是否存在method.__self__,是一类,如马亭的回答,但不要求访问类本身。

相关问题