为什么不为子类调用我的元类函数?

时间:2014-08-20 12:59:26

标签: python python-2.7 metaclass

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的重复,但它们是一个类,而不是一个函数,作为一个元类。)

1 个答案:

答案 0 :(得分:5)

答案在precedence rules for __metaclass__ lookup

  

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

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

如果我们检查Foo.__class__,我们发现它是<type 'type'>,这可以作为您的元类函数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而不仅仅是callables的原因是使它们可以继承。