By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,154 Members | 949 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,154 IT Pros & Developers. It's quick & easy.

replace mothod for only one object but not for a class

P: n/a
Hi,

I have multiple objects all belonging to the same class
(which I didn't implement and whose code I don't want to modify)

Now I'd like to change one method for one object only (after it has
been created) without adding any overhead
to the call of the other object's methods.
Is this possible?

Example
##### This is NOT what I'd like to do
##### as it overwrites the method for all objects of this class
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
aclass.method = mymethod
o1.method() # now new method
o2.method() # now new method
####### What doesn't work, but what I'd like to do
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
o1.method = mymethod
o1.method() # now new method
o2.method() # still old method
thanks for any pointers.
P.S. I guess, that there is a computer science term for what I try to
achieve.
If anybody knew it I would be interested to learn it as well.

Oct 14 '08 #1
Share this Question
Share on Google+
10 Replies


P: n/a
from functools import partial

class Point:
def __init__(self, x, y):
self.x, self.y = x, y

def show(self, n):
for i in range(n):
print "Point: (%s, %s)" % (self.x, self.y)

def new_method(obj, func):
def method(*args, **kw):
return func(obj, *args, **kw)

return method
p1 = Point(1, 2)
p2 = Point(3, 4)

def show(self, n):
print "Not a Point: %s-%s" % (self.x, self.y)
p2.show = partial(show, p2)

p1.show(3)
p2.show(3)

HTH,
--
Miki <mi*********@gmail.com>
http://pythonwise.blogspot.com
Oct 14 '08 #2

P: n/a
On Oct 14, 1:50 pm, hofer <bla...@dungeon.dewrote:
Hi,

I have multiple objects all belonging to the same class
(which I didn't implement and whose code I don't want to modify)

Now I'd like to change one method for one object only (after it has
been created) without adding any overhead
to the call of the other object's methods.

Is this possible?

Example
##### This is NOT what I'd like to do
##### as it overwrites the method for all objects of this class
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
aclass.method = mymethod
o1.method() # now new method
o2.method() # now new method

####### What doesn't work, but what I'd like to do
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
o1.method = mymethod
o1.method() # now new method
o2.method() # still old method

thanks for any pointers.
Please post the actual code that doesn't work. The following works as
expected:
>>class A(object):
... def foo(self): return 'Original'
...
>>a = A()
b = A()
a.foo()
'Original'
>>b.foo()
'Original'
>>b.foo = lambda: 'Modified'
a.foo()
'Original'
>>b.foo()
'Modified'
HTH,
George
Oct 14 '08 #3

P: n/a
On Oct 14, 11:20*am, George Sakkis <george.sak...@gmail.comwrote:
On Oct 14, 1:50 pm, hofer <bla...@dungeon.dewrote:
Hi,
I have multiple objects all belonging to the same class
*(which I didn't implement and whose code I don't want to modify)
Now I'd like to change one method for one object only (after it has
been created) without adding any overhead
to the call of the other object's methods.
Is this possible?
Example
##### This is NOT what I'd like to do
##### as it overwrites the method for all objects of this class
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
aclass.method = mymethod
o1.method() # now new method
o2.method() # now new method
####### What doesn't work, but what I'd like to do
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
o1.method = mymethod
o1.method() # now new method
o2.method() # still old method
thanks for any pointers.

Please post the actual code that doesn't work. The following works as
expected:

* * >>class A(object):
* * ... * * def foo(self): return 'Original'
* * ...
* * >>a = A()
* * >>b = A()
* * >>a.foo()
* * 'Original'
* * >>b.foo()
* * 'Original'
* * >>b.foo = lambda: 'Modified'
* * >>a.foo()
* * 'Original'
* * >>b.foo()
* * 'Modified'

HTH,
George
What you're doing is called monkeypatching. I consider it dangerous,
but to each his own. Python's metaprogramming facilities can handle
it.

The lambda approach can leak, I've had garbage collection issues when
shuffling around bound methods (my objects weren't being collected
when expected, basically). The partial approach is cool, too, but it
won't reliably work with things like __getattr__ and __setattr__,
which I also learned the hard way. The probable best way of going
about it is to define a new class that implements your one method, and
use some on-the-fly magic to create a NEW class that inherits from
both your monkeypatch class and your current instance's class:

In [2]: class main_implementation(object):
...: def a(self):
...: print 'a'
...: def b(self, argb='b'):
...: print 'B says %r' % argb
...:
...:

In [6]: class new_implementation_of_a(object):
...: def a(self):
...: print "This is a new implementation of A"
...:
...:

In [7]: mymain = main_implementation()

In [8]: mymain.a()
a

In [9]: mymain.__class__ = type(mymain.__class__.__name__+'MODIFIED',
(new_implementation_of_a, mymain.__class__), {})

In [10]: mymain
Out[10]: <__main__.main_implementationMODIFIED object at 0x0137EA50>

In [11]: mymain.a()
This is a new implementation of A

In [12]: mymain.b()
B says 'b'

The magic here occurs when you create a new class on-the-fly using the
type() built-in function and assign it to the instance's __class__
attribute.

Good luck.
Oct 14 '08 #4

P: n/a
Bruno Desthuilliers wrote:
If the class is a new-style one [1], it just requires invoking the
descriptor protocol by yourself to get a bound method, ie:
Another note about new style classes:
You can NOT overwrite most magic methods (__*__) on the instance. Most
magic methods are only looked up on the class object.

Christian

Oct 14 '08 #5

P: n/a
On Oct 14, 12:28 pm, Bruno Desthuilliers
<bdesth.quelquech...@free.quelquepart.frwrote:
George Sakkis a écrit :
On Oct 14, 1:50 pm, hofer <bla...@dungeon.dewrote:
Hi,
I have multiple objects all belonging to the same class
(which I didn't implement and whose code I don't want to modify)
Now I'd like to change one method for one object only (after it has
been created) without adding any overhead
to the call of the other object's methods.
Is this possible?
Example
##### This is NOT what I'd like to do
##### as it overwrites the method for all objects of this class
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
aclass.method = mymethod
o1.method() # now new method
o2.method() # now new method
####### What doesn't work, but what I'd like to do
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
o1.method = mymethod
o1.method() # now new method
o2.method() # still old method
thanks for any pointers.
Please post the actual code that doesn't work. The following works as
expected:
>>class A(object):
... def foo(self): return 'Original'
...
>>a = A()
>>b = A()
>>a.foo()
'Original'
>>b.foo()
'Original'
>>b.foo = lambda: 'Modified'
>>a.foo()
'Original'
>>b.foo()
'Modified'

Except that b.foo is a plain function, not a method:
>>class A(object):
... def foo(self): return "original called on %s" % self
...
>>a = A()
>>b = A()
>>a.foo()
'original called on <__main__.A object at 0xb7c0c56c>'
>>b.foo()
'original called on <__main__.A object at 0xb7c0c4ec>'
>>b.foo = lambda: "modified called on %s" % self
>>b.foo
<function <lambdaat 0xb7bfe9cc>
>>b.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
NameError: global name 'self' is not defined
>>b.foo = lambda self: "modified called on %s" % self
>>b.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() takes exactly 1 argument (0 given)
>>>
You're right of course; that's what you get with minimal testing ;)
Still it works with a small modification, binding self to b as default
argument:

b.foo = lambda self=b: "modified called on %s" % self

The functools.partial() solution shown before is the generalization of
this for more than one arguments. So I'm wondering, except for the
callable's exact type (bound method vs function vs functools.partial
object) is there any other difference and a reason to prefer one over
the other ? If not, functools.partial() seems more readable than
calling explicitly the descriptor.

George
Oct 14 '08 #6

P: n/a
George Sakkis a écrit :
(snip)
You're right of course; that's what you get with minimal testing ;)
Still it works with a small modification, binding self to b as default
argument:

b.foo = lambda self=b: "modified called on %s" % self
Ok, now with a real use case : use a named function instead of a lambda,
and define the function before having access to b !-)
The functools.partial() solution shown before is the generalization of
this for more than one arguments. So I'm wondering, except for the
callable's exact type (bound method vs function vs functools.partial
object) is there any other difference and a reason to prefer one over
the other ?
Consistency ? Possibly performances (NB : not benchmarked - might be
worth a little homework to check this out) ?
If not, functools.partial() seems more readable than
calling explicitly the descriptor.
Perhaps is it just me starting to getting senile and resistant to new
ideas, but while it does indeed work, I see the partial() solution as a
WTF. Invoking function.__get__ *is* the obvious[1] way to get a bound
method from a function.

[1] for anyone that know how Python turns functions into methods, that is...

But indeed, methods are specialized partial applications, and your
solution is perfectly valid.
Oct 15 '08 #7

P: n/a
Bruno Desthuilliers a écrit :
hofer a écrit :
>Hi,

I have multiple objects all belonging to the same class
(which I didn't implement and whose code I don't want to modify)

Now I'd like to change one method for one object only (after it has
been created) without adding any overhead
to the call of the other object's methods.
Is this possible?

Yes.

If the class is a new-style one [1], it just requires invoking the
descriptor protocol by yourself to get a bound method, ie:
(snip)

If it's a classic class, you can get by using either new.instancemethod
or types.MethodType:
Either I'm starting to get old or I need some vacations... Manually
invoking function.__get__(obj, type(obj)) also work with classic
classes, of course.

(snip)
Oct 15 '08 #8

P: n/a
On Oct 14, 7:50*pm, hofer <bla...@dungeon.dewrote:
Hi,

I have multiple objects all belonging to the same class
*(which I didn't implement and whose code I don't want to modify)

Now I'd like to change one method for one object only (after it has
been created) without adding any overhead
to the call of the other object's methods.

Is this possible?

Example
##### This is NOT what I'd like to do
##### as it overwrites the method for all objects of this class
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
aclass.method = mymethod
o1.method() # now new method
o2.method() # now new method

####### What doesn't work, but what I'd like to do
o1 = aclass()
o2 = aclass()
# call original method
o1.method()
o2.method()
# overwrite the method for the entire class
o1.method = mymethod
o1.method() # now new method
o2.method() # still old method

thanks for any pointers.

P.S. I guess, that there is a computer science term for what I try to
achieve.
If anybody knew it I would be interested to learn it as well.

Thanks a lot this works.
Though I must admint, that even after reading the doc I don't really
understand why.
Oct 15 '08 #9

P: n/a
Hi
hofer a écrit :
I have multiple objects all belonging to the same class
(which I didn't implement and whose code I don't want to modify)
Now I'd like to change one method for one object only (after it has
been created) without adding any overhead
to the call of the other object's methods.
Thanks for all of your answers:

Here an example with three of the suggested solutions:
(I didn't succeed in implementing Jason's solution with my
example)

################################################## ######
import threading
# some objects
a = threading.Event()
b = threading.Event()
c = threading.Event()
d = threading.Event()

def run_dly(o): # a test function
print o,"start",
o.wait(1)
print "stop"

# unmodified test
run_dly(a)
run_dly(b)
run_dly(c)
run_dly(d)

# The new Method
def verbose_wait(self,dly):
print "VERBOSE",
threading._Event.wait(self,dly)

### Implemented with partial
from functools import partial
b.wait = partial(verbose_wait,b)

### with __get__ for new classes
c.wait = verbose_wait.__get__(c,type(c))

## with new for old classes
import new
d.wait = new.instancemethod(verbose_wait,d,type(d))

run_dly(a)
run_dly(b)
run_dly(c)
run_dly(d)
############# end
thanks again

Hofer

Oct 15 '08 #10

P: n/a
hofer a écrit :
Hi
>>hofer a écrit :
I have multiple objects all belonging to the same class
(which I didn't implement and whose code I don't want to modify)
Now I'd like to change one method for one object only (after it has
been created) without adding any overhead
to the call of the other object's methods.

Thanks for all of your answers:

Here an example with three of the suggested solutions:
(I didn't succeed in implementing Jason's solution with my
example)

################################################## ######
import threading
# some objects
a = threading.Event()
b = threading.Event()
c = threading.Event()
d = threading.Event()

def run_dly(o): # a test function
print o,"start",
o.wait(1)
print "stop"

# unmodified test
run_dly(a)
run_dly(b)
run_dly(c)
run_dly(d)

# The new Method
def verbose_wait(self,dly):
print "VERBOSE",
threading._Event.wait(self,dly)
Note that given your use case, you could have used a decorator here
instead...

def verbose(method):
def _verbose(*args, **kw):
print "%s called on %s" % (method.__name__, method.im_self)
print "args : ", args, " - kwargs : ", kw
return method(*args, **kw)

_verbose.__name__ = "verbose wrapper for %s" % method.__name__
return _verbose

b.wait = verbose(b.wait)

Or if you want a more extensible - and "reversible" - solution:
class VerboseMethod(object):
def __init__(self, method, before=None, after=None):
# we only want bound methods here
obj = getattr(method, "im_self", None)
if obj is None:
err = "%s expected a bound method, got %s" % (
type(self), method
)
raise ValueError(err)

self._method = method
self._before = before
self._after = after

def _verbose_before(self, *args, **kw):
"""
You subclass VerboseMethod and taylor this to your own needs,
or alternatively pass a 'before' callback to VerboseMethod
that will get called with method, *args, **kw
"""
if callable(self._before):
self._before(self._method, *args, **kw)
return
# default
m = self._method
print "%s about to be called on %s" % (m.__name__, m.im_self)
print "args : ", args, " - kwargs : ", kw

def _verbose_after(self, result, *args, **kw):
"""
You subclass VerboseMethod and taylor this to your own needs,
or alternatively pass an 'after' callback to VerboseMethod
that will get called with method, result, *args, **kw
"""
if callable(self._after):
self._after(self._method, result, *args, **kw)
return
# default
m = self._method
print "%s called on %s" % (m.__name__, m.im_self)
print "args : ", args, " - kwargs : ", kw
print "result : ", result

def __call__(self, *args, **kw):
self._verbose_before(*args, **kw)
result = self._method(*args, **kw)
self._verbose_after(result, *args, **kw)
return result

def drop(self):
"""restore the original method..."""
obj = self._method.im_self
delattr(obj, self._method.__name__)

class B(object):
def __init__(self, name):
self.name = name

def wait(self, dly=42):
return "%s.wait(%s)" % (self.name, dly)

b1 = B('b1')
b2 = B('b2')

print b1.wait()
print b2.wait()

b1.wait = VerboseMethod(b1.wait)
print b1.wait()
print b2.wait()

b1.wait.drop()
print b1.wait()
print b2.wait()

def before(m, *args, **kw):
print "test before"
print m, args, kw
def after(m, r, *args, **kw):
print "test after"
print m, r, args, kw

b1.wait = VerboseMethod(b1.wait, before=before, after=after)
print b1.wait()
print b2.wait()

b1.wait.drop()
print b1.wait()
print b2.wait()
HTH
Oct 15 '08 #11

This discussion thread is closed

Replies have been disabled for this discussion.