[Tutor] monkey patching question

Albert-Jan Roskam fomcl at yahoo.com
Tue Feb 17 22:53:18 CET 2015


Hi,

I would like to monkey patch a function 'decode' that is defined inside a class. It is defined there because it is a logical place, next to its counterpart *method* 'encode'. I can successfully monkey patch meth1, but when I call meth2, it does not use the patched decorator. How can this be done? In this example, I would like to effectively "turn off" @decode. I am hoping for a solution that works on Python 2.7 and 3.3+.


import inspect, functools
class Foo(object):

    def decode(func):
        @functools.wraps(func)
        def wrapped(*args, **kwargs):
            print "original decorator was called"
            return func(*args, **kwargs).decode("utf-8")
        return wrapped
       
    def encode(self):
        """this is just here to show why decode() is defined
        within Foo"""
        pass

    def meth1(self):
        return "original method was called"

    @decode
    def meth2(self):
        return b"python rocks"


# ---- works -----
f = Foo()
print f.meth1()
Foo.meth1 = lambda self: "new method was called"
print f.meth1()
print "-------------------"


# ---- does not work -----
def patched_decode(func):
    @functools.wraps(func)
    def wrapped(*args, **kwargs):
        print "patched decorator was called"
        return func(*args, **kwargs)
    return wrapped

f = Foo()
print 'ORIGINAL'
print inspect.getsource(Foo.decode)  # shows source code of regular decode (as expected)
result = f.meth2()
print repr(result), type(result)

#setattr(Foo, "decode", patched_decode)
Foo.decode = patched_decode

print 'PATCHED'
print inspect.getsource(f.decode)  # shows source code of patched_decode (as expected)
result = f.meth2()
print repr(result), type(result)   # not patched at all! it's still unicode!



##### output:
In [1]: %run monkey_patch.py
original method was called
new method was called
-------------------
ORIGINAL
def decode(func):
           @functools.wraps(func)
    def wrapped(*args, **kwargs):
        print "original decorator was called"
        return func(*args, **kwargs).decode("utf-8")
    return wrapped

original decorator was called
u'python rocks' <type 'unicode'>
PATCHED
def patched_decode(func):
       @functools.wraps(func)
    def wrapped(*args, **kwargs):
        print "patched decorator was called"
        return func(*args, **kwargs)
    return wrapped

original decorator was called
u'python rocks' <type 'unicode'>
 
Regards,

Albert-Jan




~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

All right, but apart from the sanitation, the medicine, education, wine, public order, irrigation, roads, a 

fresh water system, and public health, what have the Romans ever done for us?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 


More information about the Tutor mailing list