Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't monkey-patched methods get passed a reference to the instance?

See this example for a demonstration:

>>> class M:
       def __init__(self): self.x = 4
>>> sample = M()
>>> def test(self):
        print(self.x)
>>> sample.test = test
>>> sample.test()
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    sample.test()
TypeError: test() missing 1 required positional argument: 'self'

Why?

like image 349
temporary_user_name Avatar asked Apr 15 '14 02:04

temporary_user_name


2 Answers

The test method you are assigning to sample.test is not bound to the sample object. You need to manually bind it like this

import types
sample.test = types.MethodType(test, sample)
sample.test()
# 4
like image 184
thefourtheye Avatar answered Nov 04 '22 13:11

thefourtheye


Functions are objects like any other and there needs to be consistency on what happens when objects are assigned to names, regardless of where the names are (i.e. in local namespace or on as attributes on an object).

When you define a function with def you are binding a function to the name after def, and when you do assignment like some_object.f = my_function you are also binding the function to a name. There's no magic in the assignment process that would change the nature of the function.

There is magic in the class definition process. Functions defined as instance methods (that is, functions defined inside a class definition) are not simply assigned as attributes to instances, but instead they are bound to the instance using a descriptor.

like image 36
Andrew Gorcester Avatar answered Nov 04 '22 13:11

Andrew Gorcester