How about this (note the first argument 'self' which is the instance
itself in the second case):
def method_for_instance( message ):
print message
def method_for_class( self, message ):
print message
class myClass( object ):
pass
inst = myClass( )
inst.method = method_for_instance
inst.method( 'hello' )
myClass.method = method_for_class
inst = myClass( )
inst.method( 'hello' )
I think a solution may be using the new module and the function
instancemethod:
instancemethod(function, instance, class)
This function will return a method object, bound to instance, or
unbound if instance is None. function must be callable.
./alex
--
.w( the_mindstorm )p.
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)
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).
HTH
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).
> 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.
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
Another way is to use the 'types' module:
In [1]: class T(object):
...: pass
...:
In [2]: t = T()
In [3]: import types
In [5]: types.MethodType?
Type: type
Base Class: <type 'type'>
String Form: <type 'instancemethod'>
Namespace: Interactive
Docstring:
instancemethod(function, instance, class)
Create an instance method object.
In [10]: m = types.MethodType(lambda self: 3, t, T)
In [11]: t.m = m
In [12]: t.m()
Out[12]: 3
--
Lawrence, oluyede.org - neropercaso.it
"It is difficult to get a man to understand
something when his salary depends on not
understanding it" - Upton Sinclair
True - and that's somewhat cleaner since it doesn't expose the internals
of the descriptor protocol. OTHO, it can lead to strange results with
callables not implementing the descriptor protocol:
class MyCallable(object):
def __init__(self, name):
self.name = name
def __call__(self):
print self.name
fun = MyCallable('gizmo')
class Foo(object):
pass
f = Foo()
f.fun = types.MethodType(fun, f, Foo)
f.fun()
=>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/python-17437zds.py", line 16, in <module>
f.fun()
TypeError: __call__() takes exactly 1 argument (2 given)
<snip>
Actually, the result is not "strange" at all if you understand what's
going. The reason you got an exception is because your __call__()
method only takes a single argument (the implicit self argument, which
is the instance of MyCallable). However, if you define it with two
arguments it works just fine:
>>> class MyCallable(object):
... def __call__(self, inst):
... print self, inst
...
>>> class Foo(object):
... pass
...
>>> fun = MyCallable()
>>> f = Foo()
>>> f.fun = types.MethodType(fun, f, Foo)
>>> f.fun()
<__main__.MyCallable object at 0x648d0> <__main__.Foo object at
0x64810>
>>>
~ Daniel
Don't worry, *I* do exactly know what's going on !-)
But we all here know that newbies already tend to get confused (or at
least perplexed) by the error message they get when they forgot the self
argument in methods definition... FWIW, I did experiment this situation
a couple years ago, whith a coworker that, while proficient with C and
Perl, was somewhat new to Python. He banged his head against the wall
for near an hour before asking for help, and it took me quite a couple
of minutes to figure out what was going wrong.