I know if you want to add a method to a class instance you can't do a simple assignment like this:
>>> def print_var(self): # method to be added
print(self.var)
>>> class MyClass:
var = 5
>>> c = MyClass()
>>> c.print_var = print_var
this indeed would cause print_var
to behave like a normal function, so the self
argument wouldn't have his typical meaning:
>>> c.print_var
<function print_var at 0x98e86ec>
>>> c.print_var()
Traceback (most recent call last):
File "<pyshell#149>", line 1, in <module>
c.print_var()
TypeError: print_var() takes exactly 1 argument (0 given)
In order to let the function be considered a method (i.e. to bind it to the instance), I used to use this code:
>>> import types
>>> c.print_var = types.MethodType(print_var, c)
>>> c.print_var
<bound method MyClass.print_var of <__main__.MyClass object at 0x98a1bac>>
>>> c.print_var()
5
but I found that .__get__
may also be used for this purpose:
>>> c.print_var = print_var.__get__(c)
>>> c.print_var
<bound method MyClass.print_var of <__main__.MyClass object at 0x98a1bac>>
>>> c.print_var()
5
The problem here is that it just works, but I can't understand how and why. The documentation about .__get__
doesn't seem to help very much.
I'd appreciate if someone could clarify this behaviour of python's interpreter.
The information you're looking for is in the Descriptor HowTo Guide:
To support method calls, functions include the
__get__()
method for binding methods during attribute access. This means that all functions are non-data descriptors which return bound or unbound methods depending whether they are invoked from an object or a class. In pure Python, it works like this:
class Function(object):
. . .
def __get__(self, obj, objtype=None):
"Simulate func_descr_get() in Objects/funcobject.c"
return types.MethodType(self, obj)
So there really isn't anything strange going on -- the __get__
method of a function object calls types.MethodType
and returns the result.
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