Reputation: 782
I am trying to understand the self reference in a patched method. The code is the following:
class foo():
def __init__(self):
self.child = lambda: none
self.child.string = "child's string value"
self.string = "string value 1"
print "initialized"
def func1(self):
print self.string
if __name__=="__main__":
foo0=foo()
foo0.newMethod = lambda: "test"
print foo0.newMethod()
foo0.func1()
foo0.child.secondMethod = foo0.func1
foo0.child.secondMethod()
Why does the child's method refer its self to foo0? Is this any different from javascript?
Upvotes: 0
Views: 92
Reputation: 8910
The answer to that question lies in Python's distinction between unbound method and bound methods. When you define a method, it's unbound: it can operate on any instance of the class, and it is, in fact, nothing more than a function whose first argument is named self (and even then, it's a convention) and a little bit of checking so you don't do truly horrible things with them.
class Foo(object):
def my_method(self, arg):
print "self:", self
print "arg:", arg
a = Foo()
print Foo.my_method(a, 2)
# self: self: <__main__.Foo object at 0x000000000219DE10>
# arg: 2
# You could, in theory, do that, but Python complains because it values the sanity
# of the people who will have to maintain your code :p
print Foo.my_method(1, 2)
# TypeError: unbound method my_method() must be called with Foo instance as first argument (got int instance instead)
So far, nothing special. However, Python has a bit of magic when we call a method not on the class itself (as is done above), but on an instance of that class (that is, on an object).
a.my_method(2)
# self: <__main__.Foo object at 0x000000000219DE10>
# arg: 2
Notice how suddenly you only have to supply arg
to the method, even though it's defined with two arguments? That's because a.my_method
is a bound method: it's the my_method
method of the a
object, not that of the Foo
class. It is bound to that particular instance, and has a reference to that particular object in it (if you look at dir(a.my_method)
, you'll notice it has a im_self
attribute).
However, in your example, if you were to add a print self
statement in func1
, it would print foo0
instead of foo0.child
. That's because the "binding" happens not when you call the method (foo0.child.secondMethod()
), but simply when you reference it (foo0.func1
).
More importantly, it only ever happens when you reference a method that you defined on a class.
So in your example, foo0.child.secondMethod = foo0.func1
references foo0
's func1
method (which gives you a bound method of foo0
), but no magic is performed in the assignment itself. It's simply setting an attribute of foo0.child
.
Does that make sense?
Upvotes: 1