Check if a function uses @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.


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

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

If the object is a method object, and so has a method.__self__ attribute, and that attribute is the class you got the attribute from, then it'll take the class as the first argument. It has been bound to the class.

Note that you already have a bound object at this point, so you don't need to pass in the class again, unless you first extract the original function from method.__func__.

Here is an illustration, the class Foo has a class method bar and a regular method baz, which is not bound when you access it directly on the class:

>>> class Foo:
...     @classmethod
...     def bar(cls):
...         pass
...     def baz(self):
...         pass
... 
>>> Foo.baz
<function Foo.baz at 0x1097d1e18>
>>> Foo.bar
<bound method Foo.bar of <class '__main__.Foo'>>
>>> Foo.bar.__self__
<class '__main__.Foo'>
>>> Foo.bar.__self__ is Foo
True

Calling Foo.bar() automatically passes in Foo.bar.__self__ as the first argument.

If you need to test such methods, use inspect.ismethod(), and if that returns True test the __self__ attribute:

import inspect

if inspect.ismethod(cls.method) and cls.method.__self__ is cls:
    # method bound to the class, e.g. a classmethod

This should work for any custom descriptors that work like classmethod does, as well.

If you need to know with certainty that the method was produced by a classmethod object, you'll need to look up the attributes directly in the class namespace (cls.__dict__ or vars(cls)), and do so in each class in the class hierarchy in method resolution order:

def isclassmethod(method):
    bound_to = getattr(method, '__self__', None)
    if not isinstance(bound_to, type):
        # must be bound to a class
        return False
    name = method.__name__
    for cls in bound_to.__mro__:
        descriptor = vars(cls).get(name)
        if descriptor is not None:
            return isinstance(descriptor, classmethod)
    return False

and a full test of the above two approaches using a base class and a derived class, with a custom descriptor that binds a function the same way a classmethod would, but is not, itself, a classmethod:

>>> class notclassmethod:
...     def __init__(self, f):
...         self.f = f
...     def __get__(self, _, typ=None):
...         return self.f.__get__(typ, typ)
...
>>> class Base:
...     @classmethod
...     def base_cm(cls): pass
...     @notclassmethod
...     def base_ncm(cls): pass
...     def base_m(self): pass
...
>>> class Derived(Base):
...     @classmethod
...     def derived_cm(cls): pass
...     @notclassmethod
...     def derived_ncm(cls): pass
...     def derived_m(self): pass
...
>>> inspect.ismethod(Derived.base_cm) and Derived.base_cm.__self__ is Derived
True
>>> inspect.ismethod(Derived.base_ncm) and Derived.base_ncm.__self__ is Derived
True
>>> inspect.ismethod(Derived.base_m) and Derived.base_m.__self__ is Derived
False
>>> inspect.ismethod(Derived.derived_cm) and Derived.derived_cm.__self__ is Derived
True
>>> inspect.ismethod(Derived.derived_ncm) and Derived.derived_ncm.__self__ is Derived
True
>>> inspect.ismethod(Derived.derived_m) and Derived.derived_m.__self__ is Derived
False
>>> isclassmethod(Derived.base_cm)
True
>>> isclassmethod(Derived.base_ncm)
False
>>> isclassmethod(Derived.base_m)
False
>>> isclassmethod(Derived.derived_cm)
True
>>> isclassmethod(Derived.derived_ncm)
False
>>> isclassmethod(Derived.derived_m)
False

The isclassmethod() function correctly distinguishes between the classmethod and notclassmethod descriptors.


Historical note: this answer included references to Python 2, but with Python 2 having reached EOL were removed as no longer relevant.


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