replace mothod for only one object but not for a class

Jason Scheirer jason.scheirer at gmail.com
Tue Oct 14 14:41:08 EDT 2008


On Oct 14, 11:20 am, George Sakkis <george.sak... at gmail.com> wrote:
> On Oct 14, 1:50 pm, hofer <bla... at dungeon.de> wrote:
>
>
>
> > 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.



More information about the Python-list mailing list