Dynamic method

Bruno Desthuilliers bruno.42.desthuilliers at wtf.websiteburo.oops.com
Wed Jul 11 11:00:37 CEST 2007


Daniel Nogradi a écrit :
(snip)
>> > def method_for_instance( message ):
>> >    print message
>> >
>> > class myClass( object ):
>> >    pass
>> >
>> > inst = myClass( )
>> > inst.method = method_for_instance
>> >
>> > inst.method( 'hello' )
(snip)
>> This won't work as expected:
>>
>> class Bidule(object):
>>    def __init__(self, name):
>>      self.name = name
>>
>> def greet(self, who):
>>    print "hello %s, my name is %s" % (who, self.name)
>>
>> b = Bidule('Bruno')
>> b.greet = greet
>> b.greet('Daniel')
>>
>> =>
>> Traceback (most recent call last):
>>    File "<stdin>", line 1, in <module>
>>    File "/tmp/python-23258Nq5.py", line 10, in <module>
>>      b.greet('Daniel')
>> TypeError: greet() takes exactly 2 arguments (1 given)
> 
> 
> Well, I thought the name method_for_instance and method_for_class are
> clear enough that if you want to 'attach' one of them to an instance
> then method_for_instance should be used :)
> And method_for_instance has only one argument and so will work as in
> the example I gave (I guess you just overlooked them).

I didn't overlooked anything. *You* did. Your "method_for_instance" is 
*not* a method - it's a function. It's easy to check this out:

>>> class Toto(object):
...     def truc(self):
...             print "%s.truc" % self
...
>>> def chose():
...     print "in chose, no 'self' here"
...
>>> t = Toto()
>>> t.truc
<bound method Toto.truc of <__main__.Toto object at 0xb7925c0c>>
>>> t.chose = chose
>>> t.chose
<function chose at 0xb7db541c>
>>> 

The whole point of methods is that they do have access to the object 
(instance or class) - which is not the case of your 
"method_for_instance". Please reread the following:

> 
>> The point is that Python functions are descriptor objects that, when
>> looked up, return a (bound or unbound) method object wrapping
>> themselves. So to attach functions as method *on a per-instance basis*,
>> you either need to use new.instancemethod (as explained by Alex), or
>> directly use the descriptor protocol, ie:
>>
>> b.greet = greet.__get__(b)
>> b.greet('Daniel')
>> => hello Daniel, my name is Bruno
>>
>> Note that you don't need this to attach a function as method to a class
>> - the descriptor protocol will then JustWork(tm).
> 
> 
> I agree that in general the solution explained by Alex and you is better.

They are not "better" - they are correct.

HTH



More information about the Python-list mailing list