在普通的Python代码中,实际创建具有二进制结构和所有所需字段的内存类对象的唯一调用是
type.__new__
. 使用元类这样的可调用函数只需实例化
type
可以使用本机C代码,甚至在纯Python中创建另一个“基本元类”,调用本机OS内存分配函数并填充相同的内容
structure defined for a "type object"
,但是,这只能完成完全相同的任务
已经这样做了,所以这将是一个复杂的、容易出错的、无法进一步改进的轮子的重新发明,因为产生的二进制布局必须与该结构中定义的相同(即,实现“神奇功能”的方法的指针,如
__init__
__geitem__
以此类推,必须与结构中的偏移量相同)
(此结构中数据的附加字段,甚至精致值都可以通过代码继承类型来完成—因此无论如何都可以通过普通元类来完成)
类型。\u新__
(函数通过调用
类型
__class__
属性)是有效的元类。如果元类以
__metaclass__
类型
,也就是元类本身。否则,如果它是一个普通函数,只是作为一个类工厂调用
类型
在它的主体中,有效元类只是类型。
In [1]: def function_meta(name, bases, ns):
...: return type(name, bases, ns)
...:
In [2]: class test(metaclass=function_meta):
...: pass
...:
In [3]: type(test)
Out[3]: type
In [4]: class ClassMeta(type):
...: pass
...:
...:
In [5]: class test2(metaclass=ClassMeta):
...: pass
...:
In [6]: type(test2)
Out[6]: __main__.ClassMeta
那么,为什么一个类不能从
类型
被使用?
尝试这样做时出现的错误是由于调用
类型。\u新__
In [11]: class InheritFromOther(object):
...: def __new__(mcls, name, bases, ns):
...: return type.__new__(mcls, name, bases, ns)
...: # the line above is the one that errors - as
...: # mcls here is not a subclass of type.
...: # type(name, bases, ns) would work.
In [12]: class test4(metaclass=InheritFromOther):
...: pass
...:
...:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-12-bf5b1fa4bb7f> in <module>()
----> 1 class test4(metaclass=InheritFromOther):
2 pass
<ipython-input-11-62d1fe46490b> in __new__(mcls, name, bases, ns)
1 class InheritFromOther(object):
2 def __new__(mcls, name, bases, ns):
----> 3 return type.__new__(mcls, name, bases, ns)
4
TypeError: type.__new__(InheritFromOther): InheritFromOther is not a subtype of type
类型。\u新__
使用类型为的有效子类作为第一个参数:
In [13]: class InheritFromOtherTake2(object):
...: def __new__(mcls, name, bases, ns):
...: return type.__new__(type, name, bases, ns)
...:
In [14]: class test5(metaclass=InheritFromOtherTake2):
...: pass
...:
In [15]: type(test5)
Out[15]: type
正如上面提到的,为了完整性,作为元类使用的callable确实有可能返回类型(或其子类)的实例以外的内容。在这种情况下,由
class
语句体不是一个类,但是不管调用返回什么:
In [7]: def dict_maker_meta(name, bases, ns):
...: return ns
...:
In [8]: class test3(metaclass=dict_maker_meta):
...: a = 1
...: b = 2
...: c = 'test'
...:
In [9]: type(test3)
Out[9]: dict
In [10]: test3
Out[10]:
{'__module__': '__main__',
'__qualname__': 'test3',
'a': 1,
'b': 2,
'c': 'test'}