473,394 Members | 1,812 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

replace mothod for only one object but not for a class

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
10 1424
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
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
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
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
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
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
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
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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: beliavsky | last post by:
The code for text in open("file.txt","r"): print text.replace("foo","bar") replaces 'foo' with 'bar' in a file, but how do I avoid changing text inside single or double quotes? For making...
9
by: gulu man | last post by:
Hi, What is the substitute for COM objects in .NET? How can I create something similar to com in .net? Is it still possible? Thank you
5
by: Mahesha | last post by:
Hello, I need help in replacing one string pattern with another. Ex: I have a financial security expression like log(T 3.25 6/24/2004)/sqrt(T 4.5 6/19/2002) Here "T 3.25 6/24/2004" is a...
16
by: BBM | last post by:
This is so bizarre I hesitate to post it, but I need to get this working. My code looks like this... Private Const cmdTestResourcesSel = "SELECT * FROM TResources" & _ " WHERE Scenario =...
23
by: digitalorganics | last post by:
How can an object replace itself using its own method? See the following code: class Mixin: def mixin(object, *classes): NewClass = type('Mixin', (object.__class__,) + classes, {}) newobj =...
3
by: aspineux | last post by:
Hi I would like a kind of function able to replace the base class like that: class Graph: pass class Circle(Graph): pass
10
by: Steven W. Orr | last post by:
In the program below, I want this instance to end up calling repmeth whenever inst.m1 is called. As it is now, I get this error: Hello from init inst = <__main__.CC instance at 0x402105ec>...
1
by: NvrBst | last post by:
I want to use the .replace() method with the regular expression /^ %VAR % =,($|&)/. The following DOESN'T replace the "^default.aspx=,($|&)" regular expression with "":...
6
by: Rauan Maemirov | last post by:
Hi, all. I'm trying to replace <object ...><embed... /></objectwith <imgtag and vice-verse. It's like implementation of media plugin of Tiny MCE editor. I tried to watch their code, but it's too...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.