【问题标题】:Why isn't my metaclass function getting invoked for subclasses?为什么没有为子类调用我的元类函数?
【发布时间】:2014-10-13 20:25:53
【问题描述】:

Python 文档说metaclass of a class can be any callable.我看到的所有示例都使用一个类。为什么不使用函数?它是可调用的,并且定义起来相当简单。但它不起作用,我不明白为什么。

这是我的代码:

class Foo(object):
    def __metaclass__(name, base, dict):
        print('inside __metaclass__(%r, ...)' % name)
        return type(name, base, dict)
print(Foo.__metaclass__)
class Bar(Foo):
    pass
print(Bar.__metaclass__)

这是输出:

inside __metaclass__('Foo', ...)
<unbound method Foo.__metaclass__>
<unbound method Bar.__metaclass__>

元类方法是为父类和子类定义的。为什么只为父母打电话? (是的,我尝试为我的元类使用 classmethod 和 staticmethod 装饰器,但都不起作用。是的,这似乎是 Metaclass not being called in subclasses 的复制品,但它们是一个类,而不是一个函数,作为一个元类。)

【问题讨论】:

  • 我添加了一个链接到文档的相关部分。请检查这是您的想法。

标签: python python-2.7 metaclass


【解决方案1】:

答案在precedence rules for __metaclass__ lookup

适当的元类由以下优先规则确定:

  • 如果dict['__metaclass__'] 存在,则使用它。
  • 否则,如果至少有一个基类,则使用其元类(首先查找__class__ 属性,如果未找到,则使用其类型)。
  • 否则,如果存在名为__metaclass__ 的全局变量,则使用它。
  • 否则,将使用旧式经典元类 (types.ClassType)。

如果我们检查Foo.__class__,我们会发现它是&lt;type 'type'&gt;,这应该是您的元类函数type 来构造Foo

__class__type 设置为type.__new__ 的第一个参数,这就是为什么在类元类中我们调用type.__new__(cls, name, bases, dict)(或super(Metaclass, cls).__new__(cls, ...))。但是,如果元类是一个函数,我们就不能这样做:

>>> def __metaclass__(name, base, dict):
>>>     print('inside __metaclass__(%r, %r, %r)' % (name, base, dict))
>>>     return type.__new__(__metaclass__, name, base, dict)
>>> class Foo(object):
>>>     __metaclass__ = __metaclass__
TypeError: Error when calling the metaclass bases
    type.__new__(X): X is not a type object (function)

同样,如果我们尝试将Foo.__class__ 设置为您的__metaclass__,它会失败,因为__class__ 属性必须是一个类:

>>> Foo.__class__ = Foo.__metaclass__.__func__
TypeError: __class__ must be set to new-style class, not 'function' object

因此,让元类类继承type 而不仅仅是可调用对象,是为了让它们可继承。

【讨论】:

  • 我不太明白。运行时是否尝试在某个时候将Foo.__class__ 设置为给定的__metaclass__?还是“程序员的责任”?
  • @SylvainLeroux 会自动发生如果你调用type.__new__(cls, ...)(或者,等效地,super(MyMetaclass, cls).__new__(cls, ...))。我会澄清的,谢谢。
猜你喜欢
  • 2014-04-08
  • 2015-01-16
  • 1970-01-01
  • 2015-04-24
  • 1970-01-01
  • 2023-03-26
  • 2018-08-22
  • 1970-01-01
  • 2018-01-14
相关资源
最近更新 更多