Here is an example I just played through on my machine:
$ python
Python 2.7.4 (default, Apr 19 2013, 18:28:01)
[GCC 4.7.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
# just a test class
>>> class A(object):
... def hi(self):
... print("hi")
...
>>> a = A()
>>> a.hi()
hi
>>> def hello(self):
... print("hello")
...
>>>
>>> hello(None)
hello
>>>
>>>
>>>
>>> a.hi = hello
# now I would expect for hi to work the same way as before
# and it just prints hello instead of hi.
>>> a.hi()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: hello() takes exactly 1 argument (0 given)
>>>
>>> def hello():
... print("hello")
...
# but instead this one works, which doesn't contain any
# reference to self
>>> a.hi = hello
>>> a.hi()
hello
>>>
>>>
>>>
>>>
>>> a.hello = hello
>>> a.hello()
hello
What is happening here? Why doesn't the function get the parameter self, when it is used as a method? What would I need to do, to get a reference to self inside it?
A method in a class referenced via an instance is bound to that instance, in your case:
In [3]: a.hi
Out[3]: <bound method A.hi of <__main__.A object at 0x218ab10>>
Compare to:
In [4]: A.hi
Out[4]: <unbound method A.hi>
So, to achieve the effect you probably want, do
In [5]: def hello(self):
...: print "hello"
...:
In [6]: A.hi = hello
In [7]: a.hi()
hello
Beware - this will apply to all instances of A
. But if you want to override a method on one instance only, do you really need to pass self
?
It is the way functions are accessed when they are class attributes.
A function added as a class attribute gets accessed as a descriptor. You see that if you do
class A(object):
pass
def f(*a): pass
A.f = f
print f
print A.f
print A().f
Here, you get the output
<function f at 0x00F03D70>
<unbound method A.f>
<bound method A.f of <__main__.A object at 0x00F089D0>>
The same output you'd get with
print f
print f.__get__(None, A)
print f.__get__(A(), A)
because that's the way how descriptors work.
All this - the transformation from a function to a method via the descriptor protocol - does not happen on instance attributes.
If you do
a = A()
a.f = f
then a.f
is as well read back as a function, not as a method. Thus, you should consider this at the time you do the assignment and rather do
a.f = lambda: f(a)
in order to pass a
to the function.
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