replace mothod for only one object but not for a class
Bruno Desthuilliers
bruno.42.desthuilliers at websiteburo.invalid
Wed Oct 15 07:08:16 EDT 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