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.
Unbound methods are methods that are not bound to any particular class instance yet. Bound methods are the ones which are bound to a specific instance of a class.
__get__(self, obj, type=None) : This attribute is called when you want to retrieve the information (value = obj. attr) , and whatever it returns is what will be given to the code that requested the attribute's value. gfg.
An unbound method is essentially a function with some trimmings. A 'bound method' is called that because the first argument (ie self ) is already set to a ; you can call b(10) and it works just the same way as if you had done a. fred(10) (this is actually necessary given how CPython operates).
If a function is an attribute of class and it is accessed via the instances, they are called bound methods. A bound method is one that has ' self ' as its first argument. Since these are dependent on the instance of classes, these are also known as instance methods.
Python 3 does not have unbound methods. Forget about classmethod
s 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With