检查函数是否使用@classmethod

hlt*_*hlt 12 python decorator class-method python-decorators

TL; DR如何确定函数是使用定义@classmethod还是具有相同效果的函数?


我的问题

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

@classmethod
def function(cls, ...):
Run Code Online (Sandbox Code Playgroud)

我发现了一个解决方案,以检查@staticmethod通过types模块(isinstance(foo, types.UnboundMethodType)False,如果foo是静态的,见这里),但没有找到如何做到这一点的任何东西@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
Run Code Online (Sandbox Code Playgroud)

我不知道如何实现我isclassmethod在这个例子中所谓的内容

Mar*_*ers 19

对于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
Run Code Online (Sandbox Code Playgroud)

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

将此与inspect.ismethod()用于检测Python 2和3中的类方法的故障安全方法相结合:

import inspect

if inspect.ismethod(cls.method) and cls.method.__self__ is cls:
    # class method
Run Code Online (Sandbox Code Playgroud)

method.__self__属性在Python 2.6中添加,以与Python 3保持一致.在Python 2.6和2.7中,它是别名method.im_self.


Sim*_*got 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
Run Code Online (Sandbox Code Playgroud)

  • 这仅适用于Python 3 (5认同)

bru*_*ers 5

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

isinstance(Foo.__dict__["baaz"], classmethod)
Run Code Online (Sandbox Code Playgroud)