Check if a function uses @classmethod

萝らか妹 提交于 2019-12-03 03:19:15

For Python 2, you need to test both if the object is a method, and if __self__ points to the class (for regular methods it'll be None when retrieved from the class):

>>> 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, regular methods show up as functions (unbound methods have been done away with).

Combine this with inspect.ismethod() for a fail-safe method to detect a class method in both Python 2 and 3:

import inspect

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

The method.__self__ attribute was added in Python 2.6 to be consistent with Python 3. In Python 2.6 and 2.7 it is an alias of method.im_self.

You should use inspect.ismethod. It works because classmethod binds the function to the class object. See the following 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
class Foo(object):
    @classmethod
    def baaz(cls):
        print "baaz"

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

None of the answers address the problem of identifying whether a method is decorated with class method from an instance of the class. Following code explores the class dict of an instance to distinguish between classmethod from other methods.

class MyClass(object):
    @classmethod
    def class_method(cls):
        pass

    def instance_method(self):
        pass

    @staticmethod
    def static_method(): 
        pass

    def blas(): pass

t = MyClass()
isinstance(t.__class__.__dict__[t.class_method.__name__], classmethod)    # True
isinstance(t.__class__.__dict__[t.static_method.__name__], classmethod)   # False
isinstance(t.__class__.__dict__[t.instance_method.__name__], classmethod) # False
isinstance(t.__class__.__dict__[t.blas.__name__], classmethod)            # False

This will work for both Python 2 and 3.

This works for me:

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

It basically tests if method.__self__ exists and is a class, as in Martijn's answer, but does not require access to the class itself.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!