Reputation: 33
I think my example will make this easier to follow:
class x():
def a(self):
return "hello"
def b(self):
return self.a() + " world"
test = x()
print test.b() # prints "hello world" as expected
test.a = lambda(self): "hola"
print test.b() # throws error:
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# File "<stdin>", line 5, in b
# TypeError: <lambda>() takes exactly 1 argument (0 given)
Attempting to update to point x().a to another function, but when x().b calls it, it doesn't appear to pass self as the first argument.
I expected to get "hola world".
Upvotes: 3
Views: 89
Reputation: 69170
Functions and methods can be tricky to keep straight. A good rule of thumb is if you need it to be a method, store it on the class.
When do you need it to be a method? When the code is accessing parts of the instance or class.
In your simple example the replacement code does not access the instance, and so you could leave it a function on the instance, like so:
test.a = lambda: "hola"
and here's an example that does access the instance, with the code stored in the class (which is what you will usually want):
x.c = lambda self: self.b().upper()
or stored in the instance:
# using MethodType
import types
test.c = types.MethodType((lambda self: self.b().upper()), test)
# using partial
import functools
test.c = functools.partial((lambda self: self.b().upper()), test)
# just using the instance name, as Ryan did
test.c = lambda: test.some_attribute
While that last method will work most of the time, it does have one pitfall:
oops = test
del oops
oops.c()
Traceback (most recent call last):
File "test.py", line 42, in <module>
oops.c()
File "test.py", line 38, in <lambda>
test.c = lambda: test.some_attribute
NameError: global name 'test' is not defined
Just something to keep in mind.
Upvotes: 0
Reputation: 176920
You can see the problem if you do
print type(test.a) # <type 'function'>
print type(test.b) # <type 'instancemethod'>
If you really want to patch a
only on test
(not on all instances of x
), you can do:
import types
test.a = types.MethodType((lambda self: "hola"), test, x)
To create an object of type instancemethod
.
Upvotes: 1