Python: Get unbound class method

Question:

How can you get a not bound class method?

class Foo:
    @classmethod
    def bar(cls): pass

>>> Foo.bar
<bound method type.bar of <class '__main__.Foo'>>

Edit: This is python 3. Sorry for the confusion.

Asked By: darkfeline

||

Answers:

Python 3 does not have unbound methods. Forget about classmethods for a moment, and look at this:

>>> class Foo:
...     def baz(self): pass
>>> Foo.baz
<function __main__.baz>

In 2.x, this would be <unbound method Foo.baz>, but 3.x does not have unbound methods.

If you want to get the function out of a bound method, that’s easy:

>>> foo = Foo()
>>> foo.baz
<bound method Foo.baz of <__main__.Foo object at 0x104da6850>>
>>> foo.baz.__func__
<function __main__.baz>

In the same way:

>>> class Foo:
...     @classmethod
...     def bar(cls): pass
>>> Foo.bar
<bound method type.bar of <class '__main__.Foo'>>
>>> Foo.bar.__func__
<function __main__.bar>

Things are much more interesting in 2.x, because there actually are unbound methods to get. You can’t normally see an unbound classmethod, because the whole point is that they get bound to the class at class creation time, instead of being left unbound and then bound to each instance at instance creation time.

But really, an unbound method is just any instancemethod whose im_self is None. So, just as you can do this:

class Foo(object):
    def baz(self): pass

foo = Foo()
bound_baz = foo.baz
unbound_baz = new.instancemethod(bound_baz.im_func, None, bound_baz.im_class)

Note that bound_baz.im_func is the 2.x version of bound_baz.__func__ in 3.x—but that new.instancemethod does not have a 3.x equivalent.

The documentation says that new is deprecated in favor of types, for 3.x compatibility, and in fact, you can do this in 2.x:

unbound_baz = types.MethodType(bound_baz.im_func, None, bound_baz.im_class)

But that doesn’t work in 3.x, because MethodType does not take a class parameter, and does not allow its instance parameter to be None. And personally, when I’m doing something that is explicitly 2.x-only and cannot be ported to 3.x, I think using new is clearer.

Anyway, given a class in 2.x, you can do this:

class Foo(object):
    @classmethod
    def bar(cls): pass

bound_bar = Foo.bar
unbound_bar = new.instancemethod(bound_bar.im_func, None, bound_bar.im_class)

If you print it out, you’ll see:

<unbound method type.bar>

Or, using your example, with an old-style class:

class Foo:
    @classmethod
    def bar(cls): pass

<unbound method classobj.bar>

And yes, maybe it’s a bit of a cheat that the im_class of a classmethod for an old-style class is classobj even though that’s not Foo.__class__, but it seems like the most reasonable way to get old-style and new-style classes working similarly in all of the usual use cases.

Answered By: abarnert

Based on my experience, unbound class methods do exist in Python 3, albeit briefly. When a class method is first created, as part of a class definition, the class doesn’t yet exist, so the method is unbound. Once the class actually exists, the method is bound. In order to keep a reference to the unbound method, it must be "hidden" inside a list, dictionary, etc.; simply saving it in a class attribute isn’t sufficient.

I use this to get an unbound class method, so that I can later check other objects against its type.

    class _HasUnboundClassMethod(object):
        @classmethod
        def _classmethod(cls):
            pass  # pragma: no cover
        _methods = [ _classmethod ]

    _ClassMethodType = type(_HasUnboundClassMethod._methods[0])
Answered By: Ian Pilcher
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.