Why this doesn't work?

Bruno Desthuilliers bruno.42.desthuilliers at websiteburo.invalid
Fri Feb 19 10:23:53 CET 2010


mk a écrit :
> 
(snip)

Sorry, no time to get into details now - but I can at least provide a 
couple hints.

The first point is that, to override a method on an _instance_, you have 
to provide a method object, not a plain function - remember that the 
descriptor protocol is only invoked on _class_ attributes, not on 
instance attributes.

class Foo(object):
   def bar(self):
       print "the original bar"

def mybar(self):
    print "mybar"

 >>> f = Foo()
 >>> f.bar = mybar
 >>> f.bar()

Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/tmp/python-1287O_i.py", line 32, in <module>
     f.bar()
TypeError: mybar() takes exactly 1 argument (0 given)

 >>> type(f.bar)
<type 'function'>
 >>> f.bar is mybar
True
 >>> f.bar(f)
mybar


As you see, "bar" is here resolved as an ordinary instance attribute - 
so here it evals to the "mybar" function object. If you want it to be a 
method object, you do have to invoke the descriptor protocol manually:

 >>> f.bar = mybar.__get__(f, type(f))
 >>> f.bar
<bound method Foo.mybar of <__main__.Foo object at 0xb7e16b0c>>
 >>> f.bar()
mybar

Or alternatively, you can use the types module:
 >>> import types
 >>> f.bar = types.MethodType(mybar, f, type(f))
 >>> f.bar
<bound method Foo.mybar of <__main__.Foo object at 0xb7e16b0c>>
 >>> f.bar()
mybar


Second point is that the descriptor protocol is invoked on each and 
every lookup. So when it comes to function class attributes, you get a 
new method object each time:

 >>> f = Foo()
 >>> m1 = f.bar
 >>> m1
<bound method Foo.bar of <__main__.Foo object at 0xb7cb522c>>
 >>> m2 = f.bar
 >>> m2
<bound method Foo.bar of <__main__.Foo object at 0xb7cb522c>>
 >>> id(m1)
3084861188L
 >>> id(m2)
3083656564L
 >>> m1 is m2
False
 >>>

I think this should help you understand why your code doesn't work as 
you assumed it would !-)


PS : as a side note, a common optimization trick is to "short-circuit" 
the whole lookup / descriptor mechanism when you have to call the same 
method of the same object in a loop:

l = []
append = l.append
for i in xrange(100):
    append(i)
print l

HTH




More information about the Python-list mailing list