I was playing with metaclasses in Python 3:
class M(type):
def __new__(cls, clsname, bases, attrs):
for 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 so far, I just hook into the creation of a class, and substitute its method with... well, itself, so no wonder everything works. But with:
class M(type):
def __new__(cls, clsname, bases, attrs):
for 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, and sometimes 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 is not callable
But I just substituted its method with a lambda wrapper! What does 'str' have to do with anything? What am I doing wrong?
(Just in case it's some weird platform-dependent implementation issue, I'm using Ubuntu Server 12.04.3...)
UPDATE: fixed the name mismatch in the traceback.
attribute!=func,attributes != attrs.attributeappears to be a string object, so thecallabletest appears to be missing.funcisn't going to point to what you think it's pointing to inside the lambda. (It will refer to the last attribute you saw in your loop, which may not be callable.) To fix this, write a helper function to create the lambda, passing in the function, rather than creating it in your loop.