元类可以是任何可调用的



吸引眼球:

我认为文件可能是错误的

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

__metaclass__此变量可以是任何可调用的接受name、base和dict的参数。在创建类时而不是内置的CCD_ 2。

2.2版新增。

然而,本文认为:

Q:哇!我可以使用任何类型的对象作为__metaclass__吗?

A:否。它必须是基对象类型的子类。。。

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

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)

这个只是返回type()(而不是type.__new__())的结果,但它只是一个可调用的。返回值被用作类。你真的可以退货:

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

在这里,可调用程序生成了一个列表实例,因此Foo被绑定到一个列表。不是很有用,但__metaclass__只是被调用来产生东西,而那个东西是直接使用的。

在您的示例中,type.__new__()的第一个参数是而不是类型,并且是调用失败。mcslist结合,而不是type的(子类)。type.__new__()可以自由设置这样的限制。

现在,由于元类仍然与类对象绑定(type(ClassObj)返回它),并且它在解析类对象上的属性查找时使用(在类MRO中该属性不可用),因此将其作为type的子类通常是一个很好的主意,因为这为__getattribute__之类的东西提供了正确的实现。正是由于这个原因,type.__new__()对可以作为第一个参数传入的内容进行了限制;这是CCD_ 19附加到返回的类对象的第一个参数。

相关内容

最新更新