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
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to