元类可以调用吗?

Can metaclass be any callable?

吸引眼球:

我认为文档可能有误!

根据 Python 2.7.12 文档,3.4.3。自定义 class 创建:

__metaclass__ This variable can be any callable accepting arguments for name, bases, and dict. Upon class creation, the callable is used instead of the built-in type().

New in version 2.2.

然而,this article 认为:

Q: Wow! Can I use any type object as the __metaclass__?

A: No. It must be a subclass of the type of the base object. ...

所以我自己做了一个实验:

class metacls(list):    # <--- subclassing list, rather than type
    def __new__(mcs, name, bases, dict):
        dict['foo'] = 'metacls was here'
        return type.__new__(mcs, name, bases, dict)

class cls(object):
    __metaclass__ = metacls
    pass

这给了我:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    class cls(object):
  File "test.py", line 4, in __new__
    return type.__new__(mcs, name, bases, dict)
TypeError: Error when calling the metaclass bases
    type.__new__(metacls): metacls is not a subtype of type

那么文档真的错了吗?

不,任何可调用的都可以。在您的情况下, type.__new__() 方法有一个您违反的限制;这与您分配给 __metaclass__.

的内容无关

一个函数是可调用的:

def metaclass_function(name, bases, body):
    return type(name, bases, body)

这只是 returntype() 的结果(不是 type.__new__()),但它 只是一个可调用的 。 return 值被用作 作为 class。你真的可以 return 任何东西:

>>> class Foo(object):
...     __metaclass__ = lambda *args: []
...
>>> Foo
[]

此处的可调用对象生成了一个列表实例,因此 Foo 绑定到一个列表。不是很有用,不过只是调用了__metaclass__产生了something,那个something就直接用了

在您的示例中,type.__new__() 的第一个参数 不是类型 调用 失败. mcs 绑定到 list,而不是 type 的(subclass)。 type.__new__() 可以自由设置此类限制。

现在,因为元class 仍然绑定到 class 对象(type(ClassObj) return 它)并且在解析属性查找时使用它在 class 对象上(属性在 class MRO 中不可用),通常 honking good idea 使其成为 subclass 的 type,因为这可以让您正确实现 __getattribute__ 之类的东西。正是出于这个原因,type.__new__() 对可以作为第一个参数传入的内容进行了限制;这是 type() 附加到 class 对象的第一个参数 returned.