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

Popular posts from this blog

python - Subclassed QStyledItemDelegate ignores Stylesheet -

java - HttpClient 3.1 Connection pooling vs HttpClient 4.3.2 -

SQL: Divide the sum of values in one table with the count of rows in another -