简要记录Python3中的metaclass。注意本文是基于new-style class的。Python3中所有class都是new-style class,Python2则不同:Python2.2以前根本不支持new-style class,而从Python2.2开始,虽然支持但需要显示地声明。
一切皆对象 (1)
在Python中,一切都是对象,比如: int
, 3
, 自定义类的实例foo
,以及自定义类Foo
,所以下面的语句都打印True
:
1 | print(isinstance(3, object)) |
Foo
是对象,那么它的class是什么呢?答案是metaclass:默认情况下,Foo
是metaclass type
的实例,我们也可以自定义metaclass,见第2节。
图1
如图所示:
foo
is an instance of classFoo
.Foo
is an instance of thetype
metaclass.type
is also an instance of thetype
metaclass, so it is an instance of itself.
自定义metaclass (2)
先看这段代码:
1 | #!/usr/bin/python3 |
用图形表示:
图2
当python解析器遇见Foo()
语句时:
- 调用
Foo
的metaclass的__call__
,即调用type.__call__
,注意:不是`Foo.call. Foo.__call__
调用:Foo.__new__
Foo.__init__
当python解析器遇见Bar()
语句时:
- 调用
Bar
的metaclass的__call__
,即调用Meta.__call__
,注意:不是`Bar.call. Meta.__call__
调用:Bar.__new__
Bar.__init__
注意区分object-class的从属关系和class-class的继承关系:
- 找
__call__
时,沿着object-class的从属关系往上走。 - 找
__new__
和__init__
时才进入继承领域,沿着class-class的继承关系往上走。
所以,上面代码的输出是:
1 | Meta.__new__ enter |
上面重点解释了foo
和bar
的创建过程。但不是说一切皆对象吗?Foo
和Bar
本身是怎么创建的呢?注意main enter
之前还有两行输出,它们就是创建Bar
的过程,其实和创建实例的过程一样:
- 先调用
Bar
的class的metaclass的__call__
:沿着object-class的从属关系往上走,Bar
的class是Meta
(就是Bar的metaclass),Meta
的metaclass是type
,所以这一步调用type.__call__
,什么也没有打印。 type.__call__
调用:Meta.__new__
Meta.__init__
这里注意class的class就是它的metclass;这应该也是meta一词的来源。
另外,Foo
的的metaclass是type
,我们没有机会在它里面添加打印语句,所以Foo
的创建什么都没打印。
通过type
动态创建class (3)
下面两种方式是等价的:
1 | def plus(self, i): |
1 | class Foo: |