adding class functionality, nested scoping

Arnaud Delobelle arnodel at googlemail.com
Fri Jan 4 06:19:44 EST 2008


On Jan 4, 10:43 am, jh... at gmx.de wrote:
> Hi,

Hi

[...]
> # 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))
>

This is normal: After ERRONEOUS_enhance_all_methods is called, the
value method is the one from the last iteration of the loop. All
subsequent references to 'method' (in function _f) will return that
last value. To solve this problem you need to fix the object 'method'
is bound to in function _f:

def enhance_all_methods(cls, replacement):
    # The following binds 'method' to its current value in _f
    def replace(method):
        def _f(*args, **kwargs):
            return replacement(method, *args, **kwargs)
        return _f
    for methodname in cls.__dict__:
        if not methodname.startswith("__"):
            _f = replace(getattr(cls, methodname))
            _f.__name__ = methodname
            setattr(cls, methodname, types.MethodType(_f, None, cls))

Of course this looks more like your first version, which trims down to
the following and is probably a better option:

def enhance_all_methods(cls, replacement):
    for methodname in cls.__dict__:
        if not methodname.startswith("__"):
            enhance_method(cls, methodname, replacement)

HTH

--
Arnaud




More information about the Python-list mailing list