抓住你的眼睛:
根据Python 2.7.12文档, 3.4.3。自定义课程创建:
__metaclass__
此变量可以任何可调用接受 名称,基础和字典的参数。在创建类时,可调用 用来代替内置的type()
。2.2版中的新功能。
然而,this article认为:
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
文件真的错了吗?
答案 0 :(得分:5)
不,任何可赎回的人都可以。在您的情况下,type.__new__()
方法有违反的限制;这与您分配给__metaclass__
的内容无关。
函数是可调用的:
def metaclass_function(name, bases, body):
return type(name, bases, body)
这个只返回type()
(不是type.__new__()
)的结果,但只是一个可调用的。返回值使用作为类。你真的可以归还任何东西:
>>> class Foo(object):
... __metaclass__ = lambda *args: []
...
>>> Foo
[]
这里callable生成了一个列表实例,因此Foo
绑定到一个列表。不是很有用,但__metaclass__
只是被调用来生成某些东西,并且直接使用了某些内容。
在您的示例中,type.__new__()
的第一个参数是而不是类型,并且调用失败。 mcs
绑定到list
,而不是type
的(子类)。 type.__new__()
可以自由设置此类限制。
现在,因为元类仍然绑定到类对象(type(ClassObj)
返回它),并且在解析类对象上的属性查找时使用它(其中属性在类MRO中不可用) ,它通常是一个鸣喇叭的好主意,使其成为type
的子类,因为这为您提供了__getattribute__
之类的正确实现。正是出于这个原因,type.__new__()
限制了作为第一个参数传递的内容;它是type()
附加到返回的类对象的第一个参数。