I was wondering if anyone could explain and offer a solution to this issue:
$ cat object-override-methods.py
class A:
def foo(self):
return 1
class B:
def foo(self):
return 1
for klass in A, B:
orig_foo = klass.foo
def foo(self):
return orig_foo(self) * 2
klass.foo = foo
A().foo()
B().foo()
$ python object-override-methods.py
Traceback (most recent call last):
File "object-override-methods.py", line 15, in <module>
A().foo()
File "object-override-methods.py", line 12, in foo
return orig_foo(self) * 2
TypeError: unbound method foo() must be called with B instance as first argument (got A instance instead)
Thanks in advance.
orig_foois a global variable which changes value with each pass through the loop. After the loop is done,orig_foorefers toB.foo.The inner functions
foo(one or each pass through the loop) both use the global value fororig_foowhen they are called. So they both callB.foo(self).When calling an “unbound method” like
orig_foo, Python2 checks that the first argument is an instance of the appropriate class.A().foo()does not pass this check. (Interestingly, this check was removed in Python3, so there would be no TypeError raised, and this bug may become harder to find.)To fix this, you must bind the value of
orig_footo the appropriateklass.You can do that by making
orig_fooa local variable offoo. One way to do that is to makeorig_fooan argument offoowith a default value. Python binds default values at the time a function is defined. Soorig_foo=orig_foobinds the local variableorig_footo the current value of theklass.foo: