replace mothod for only one object but not for a class

Bruno Desthuilliers bruno.42.desthuilliers at websiteburo.invalid
Wed Oct 15 13:08:16 CEST 2008


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



More information about the Python-list mailing list