子类中未调用元类

13 投票
1 回答
2062 浏览
提问于 2025-04-15 16:12

这里是一个Python的会话。

>>> class Z(type):
    def __new__(cls, name, bases, attrs):
        print cls
        print name
        return type(name, bases, attrs)
...     
>>> class Y(object):
    __metaclass__ = Z
...     
<class '__main__.Z'>
Y
>>> class X(Y):
...     pass
... 
>>> class W(Y):
...     __metaclass__ = Z
...     
<class '__main__.Z'>
W
>>> 

在我定义了类X之后,我期待Z._new__这个方法会被调用,并且打印出两行内容,但实际上并没有发生,(是因为 metaclass会被继承吗?)

1 个回答

14

问题在于,当你调用 type 时,cls 这个参数(也就是元类对象)没有被传递过去。因此,创建并返回的类对象 Y 并没有任何关于元类 Z 的引用。

如果你把 __new__ 中的最后一行替换成

return super(Z, cls).__new__(cls, name, bases, attrs)

那么就能正常工作了。需要注意的是,尽管在 super 中使用了 cls,我们仍然需要把 cls 作为参数提供,因为这里的 super 返回的是一个未绑定的方法(想了解更多可以查看这里)。

作为使用 super 的替代方案,你也可以使用:

 return type.__new__(cls, name, bases, attrs)

重要的是,我们需要把 cls(我们的元类对象 Z)传递给类方法 __new__。更简短的形式 type(name, bases, attrs) 会把 type 自身填入 cls 参数,这显然是错误的。这个错误就像用错误的 self 参数调用实例方法一样。

我更喜欢使用 super,因为这样更符合编程风格。

撰写回答