J
jholg
Hi,
regarding automatically adding functionality to a class (basically taken
from the cookbook recipee) and Python's lexical nested scoping I have a question wrt this code:
#-----------------
import types
# minor variation on cookbook recipee
def enhance_method(cls, methodname, replacement):
'replace a method with an enhancement'
method = getattr(cls, methodname)
def _f(*args, **kwargs):
return replacement(method, *args, **kwargs)
_f.__name__ = methodname
setattr(cls, methodname, types.MethodType(_f, None, cls))
# loop over class dict and call enhance_method() function
# for all methods to modify
def enhance_all_methods(cls, replacement):
for methodname in cls.__dict__:
if not methodname.startswith("__"):
method = getattr(cls, methodname)
def _f(*args, **kwargs):
return replacement(method, *args, **kwargs)
_f.__name__ = methodname
enhance_method(cls, methodname, replacement)
# Does not work: all enhanced methods only call the last wrapped originial
# method. It seems the name 'method' in the surrounding scope of the
# def _(...) function definition only refers to the last loop value(?)
def ERRONEOUS_enhance_all_methods(cls, replacement):
for methodname in cls.__dict__:
if not methodname.startswith("__"):
method = getattr(cls, methodname)
def _f(*args, **kwargs):
return replacement(method, *args, **kwargs)
_f.__name__ = methodname
setattr(cls, methodname, types.MethodType(_f, None, cls))
class Foo(object):
def foo(self, x):
print "foo", x
def bar(self, x):
print "bar", x
def logme(method, *args, **kwargs):
print "-->", method.__name__, args, kwargs
try:
return method(*args, **kwargs)
finally:
print "<--"
#enhance_all_methods(Foo, logme)
ERRONEOUS_enhance_all_methods(Foo, logme)
foo = Foo()
foo.foo(2)
foo.bar(2)
#-----------------
....give this output:--> foo (<__main__.Foo object at 0x1b08f0>, 2) {}
foo 2
<----> foo (<__main__.Foo object at 0x1b08f0>, 2) {}
foo 2
<--
So, while using enhance_all_methods() to add functionality does work, ERRONEOUS_enhance_all_methods() does not. Why is this? Is the explanation I tried to give in the code comment on the right track:
# Does not work: all enhanced methods only call the last wrapped originial
# method. It seems the name 'method' in the surrounding scope of the
# def _(...) function definition only refers to the last loop value(?)
Thanks for any hint,
Holger
regarding automatically adding functionality to a class (basically taken
from the cookbook recipee) and Python's lexical nested scoping I have a question wrt this code:
#-----------------
import types
# minor variation on cookbook recipee
def enhance_method(cls, methodname, replacement):
'replace a method with an enhancement'
method = getattr(cls, methodname)
def _f(*args, **kwargs):
return replacement(method, *args, **kwargs)
_f.__name__ = methodname
setattr(cls, methodname, types.MethodType(_f, None, cls))
# loop over class dict and call enhance_method() function
# for all methods to modify
def enhance_all_methods(cls, replacement):
for methodname in cls.__dict__:
if not methodname.startswith("__"):
method = getattr(cls, methodname)
def _f(*args, **kwargs):
return replacement(method, *args, **kwargs)
_f.__name__ = methodname
enhance_method(cls, methodname, replacement)
# Does not work: all enhanced methods only call the last wrapped originial
# method. It seems the name 'method' in the surrounding scope of the
# def _(...) function definition only refers to the last loop value(?)
def ERRONEOUS_enhance_all_methods(cls, replacement):
for methodname in cls.__dict__:
if not methodname.startswith("__"):
method = getattr(cls, methodname)
def _f(*args, **kwargs):
return replacement(method, *args, **kwargs)
_f.__name__ = methodname
setattr(cls, methodname, types.MethodType(_f, None, cls))
class Foo(object):
def foo(self, x):
print "foo", x
def bar(self, x):
print "bar", x
def logme(method, *args, **kwargs):
print "-->", method.__name__, args, kwargs
try:
return method(*args, **kwargs)
finally:
print "<--"
#enhance_all_methods(Foo, logme)
ERRONEOUS_enhance_all_methods(Foo, logme)
foo = Foo()
foo.foo(2)
foo.bar(2)
#-----------------
....give this output:--> foo (<__main__.Foo object at 0x1b08f0>, 2) {}
foo 2
<----> foo (<__main__.Foo object at 0x1b08f0>, 2) {}
foo 2
<--
So, while using enhance_all_methods() to add functionality does work, ERRONEOUS_enhance_all_methods() does not. Why is this? Is the explanation I tried to give in the code comment on the right track:
# Does not work: all enhanced methods only call the last wrapped originial
# method. It seems the name 'method' in the surrounding scope of the
# def _(...) function definition only refers to the last loop value(?)
Thanks for any hint,
Holger