Python 3 奇怪的元类行为

标签 python python-3.x metaclass

我正在使用 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)

到目前为止,没有什么特别的,我只是加入了一个类的创建,并将其方法替换为......好吧,它本身,所以难怪一切正常。但是:

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)

有时有效,有时无效:

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

但我只是用 lambda 包装器替换了它的方法! “str”与什么有什么关系?我做错了什么?

(以防万一出现一些奇怪的平台相关实现问题,我使用的是 Ubuntu Server 12.04.3...)

更新:修复了回溯中的名称不匹配问题。

最佳答案

进一步详细说明我的评论:

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)

这是必要的,因为在您的原始代码中,在 lambda 内部,func 引用您的 __new__ 方法返回时 func 所具有的任何值,不是创建 lambda 时的值。这是违反直觉的,但您可以验证它:

lambdas = [lambda: x for x in range(10)]
print(lambdas[0]())    # prints 9, as do lambdas[1] through [9]

为了解决这个问题,我们使用一个单独的函数来创建 lambda,从而在创建 lambda 时“卡住”func 变量的值。您还可以使用 lambda 上的默认参数值来执行此操作,但由于您在这里使用 ***,所以这有点问题。

(该行为与元类无关,您在定义 lambda 的任何地方都会看到相同的行为,并在创建它们后更改其中使用的变量的值。在这方面,lambda 与任何其他函数没有什么不同。 )

关于Python 3 奇怪的元类行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21590275/

相关文章:

python - 避免使用元类继承生成的类属性

python - 在 python3 中使用 readline 自动完成

iOS/Objective-C 元类和类别

Python 正则表达式 - "+?"如何等同于 "*"

python - 如何将所有字符串(如 "Fault")转换为唯一的 float ?

python - 如何在 Python 中对嵌套对象进行类型提示?

python-3.x - 与 aiohttp 应用程序内的 Redis(aioredis) 失去连接

grails - Groovy 元类,模拟具有 throws 子句的服务方法

python - 如何进一步优化这个文本匹配功能?

python - 如何在 python 请求 GET 中发送列表