元类编程

什么是元类

元类的定义非常简单,就是创建类的类。我们都知道,我们自己定义的类都是object的子类,但也许你不知道,所有的类的最终类型都是type.

1
2
3
4
>>> type(1)
<class 'int'>
>>> type(type(1))
<class 'type'>

元类是制造类的工厂,不过不是函数,而是类。默认情况下,python中的类是type类的实例,也就是说,type是大多数内置类和用户类的元类。

type和object的关系

为了避免无限回溯,type是其自身的实例。object是type的实例,而type是object的子类。这种关系很神奇,无法使用python代码表述,因为定义其中一个之前另一个也必须存在。

元类的用法

“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters

这里举两个简单的元类的使用例子:

禁止实例化的类

如果希望有一个类,只可以通过类方法或静态方法调用,而不允许实例化该类,这就需要通过元类来控制类的生成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class NoInstance(type):
def __call__(cls, *args, **kwargs):
raise TypeError("不能创建该类的实例")
class Jim(metaclass=NoInstance):
@staticmethod
def run():
print('Jim Run!')
---------
>>> from meta_demo import Jim
>>> j = Jim()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/mnt/hgfs/Codes/scripts/python/metacls/meta_demo.py", line 64, in __call__
raise TypeError("不能创建该类的实例")
TypeError: 不能创建该类的实例

metaclass是python3的使用方式,python2中需要使用metaclass来指定元类

单例模式

我们可以使用元类来实现单例模式,而不是用类的new方法

1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton(type):
def __init__(cls, *args, **kwargs):
cls.__instance = None
super().__init__(*args, **kwargs)
def __call__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super().__call__(*args, **kwargs)
return cls.__instance
class Dog(metaclass=Singleton):
pass

大多数时候我们并需要使用元类,也不便于维护,除非是要自己创建一个框架。