Python 3 Strange Metaclass Behaviour -
i playing metaclasses in python 3:
class m(type): def __new__(cls, clsname, bases, attrs): name, attr in attrs.items(): if callable(attr): attrs[name] = attr return type.__new__(cls, clsname, bases, attrs) class c(metaclass=m): def f(self, x): print(x) if __name__ == '__main__': c = c() c.f(1) c.f(2)
nothing special far, hook creation of class, , substitute method with... well, itself, no wonder works. with:
class m(type): def __new__(cls, clsname, bases, attrs): name, func in attrs.items(): if callable(func): attrs[name] = lambda *args, **kwds: func(*args, **kwds) return type.__new__(cls, clsname, bases, attrs)
it sometime works, , doesn't:
user$ python test.py 1 2 user$ python test.py traceback (most recent call last): file "./meta.py", line 23, in <module> main() file "./meta.py", line 19, in main instance.method(1) file "./meta.py", line 9, in <lambda> attrs[name] = lambda *args, **kwds: func(*args, **kwds) typeerror: 'str' object not callable
but substituted method lambda wrapper! 'str' have anything? doing wrong?
(just in case it's weird platform-dependent implementation issue, i'm using ubuntu server 12.04.3...)
update: fixed name mismatch in traceback.
to further elaborate on comment:
def makelambda(func): return lambda *args, **kwds: func(*args, **kwds) class m(type): def __new__(cls, clsname, bases, attrs): name, func in attrs.items(): if callable(func): attrs[name] = makelambda(func) return type.__new__(cls, clsname, bases, attrs)
this necessary because, in original code, inside lambda, func
refers whatever value func
had when __new__
method returned, not value had when lambda created. counterintuitive, can verify it:
lambdas = [lambda: x x in range(10)] print(lambdas[0]()) # prints 9, lambdas[1] through [9]
to fix that, use separate function create lambda, , "freeze" value of func
variable @ time lambda created. can default argument value on lambda, since you're using *
, **
here, little problematic.
(the behavior has nothing metaclasses, you'd see same behavior anywhere defined lambdas , changed value of variables used in them after creating them. , lambdas no different other function in respect.)
Comments
Post a Comment