To further elaborate on my comment:
def makelambda(func):
return lambda *args, **kwds: func(*args, **kwds)
class M(type):
def __new__(cls, clsname, bases, attrs):
for name, func in attrs.items():
if callable(func):
attrs[name] = makelambda(func)
return type.__new__(cls, clsname, bases, attrs)
This is necessary because, in your original code, inside the lambda, func
refers to whatever value func
had when your __new__
method returned, not the value it had when the lambda was created. This is counterintuitive, but you can verify it:
lambdas = [lambda: x for x in range(10)]
print(lambdas[0]()) # prints 9, as do lambdas[1] through [9]
To fix that, we use a separate function to create the lambda, and thus "freeze" the value of the func
variable at the time the lambda was created. You can also do this with a default argument value on the lambda, but since you're using *
and **
here, this is a little problematic.
(The behavior has nothing to do with metaclasses, you'd see the same behavior anywhere you defined lambdas and changed the value of variables used in them after creating them. And lambdas are no different from any other function in this respect.)