__metaclass__ 不是强制使用元类吗?

6 投票
3 回答
820 浏览
提问于 2025-04-15 11:23

我一直在尝试学习Python中的 metaclasses(元类)。我明白了大概的意思,但就是不知道怎么启动这个机制。我的理解是,当你构建一个类 K 时,可以通过在全局或类级别设置 __metaclass__ 为 M 来指定 M 作为这个类的元类。为了测试这个,我写了以下程序:

p = print

class M(type):
    def __init__(*args):
        type.__init__(*args)
        print("The rain in Spain")

p(1)
class ClassMeta:
    __metaclass__ = M

p(2)
__metaclass__ = M
class GlobalMeta: pass

p(3)
M('NotMeta2', (), {})

p(4)

但是,当我运行它时,得到的输出是:

C:\Documents and Settings\Daniel Wong\Desktop>python --version
Python 3.0.1

C:\Documents and Settings\Daniel Wong\Desktop>python meta.py
1
2
3
The rain in Spain
4

难道在1和2之后我不应该看到“西班牙的雨”吗?这是怎么回事呢?

3 个回答

2

在Python 3.0中,元类的语法发生了变化。以前的 __metaclass__ 属性在类和模块中都很特别,但现在不再是这样了。如果你想实现你想要的功能,需要在 class 语句中把 metaclass 作为一个关键字参数来指定:

p = print

class M(type):
    def __init__(*args):
        type.__init__(*args)
        print("The rain in Spain")

p(1)
class ClassMeta(metaclass=M): pass

这样就能得到:

1
The rain in Spain

正如你所期待的那样。

2

在Python 2.6(以及更早的版本)中,这样做是符合你预期的,但在3.0版本中,元类的指定方式有所不同:

class ArgMeta(metaclass=M): ...
14

在你使用的Python 3中,元类是通过在类定义时使用一个关键词参数来指定的:

class ClassMeta(metaclass=M):
  pass

使用 __metaclass__ 这个类属性或者全局变量的写法是Python 2.x时代的旧语法,现在已经不再支持了。想了解更多,可以查看“Python 3的新变化”PEP 2115

撰写回答