今天是 Python 专题的第 16 篇文章, 今天我们来聊聊 Python 当中的元类.
元类是 Python 当中的高级用法, 如果你之前从来没见过这个术语或者是没听说过这个概念, 这是非常正常的, 因为一方面它的使用频率不高, 另外一方面就是它相对不太容易理解. 以至于很多 Python 开发者都理解得不是很深入, 导致了市面上相关的资料也并不太多. 我也是读了一些大牛的代码才开启了这扇新世界的大门.
一切都是对象
我们之前的时候曾经介绍过, 在 Python 当中一切都是对象, 注意, 是一切都是对象. 我们都知道对象是类实例化之后的结果, 可以简单地将类和对象类比成模具和成品的关系. 模具是类, 而根据模具做出来的产品是对象.
这个比喻思想比较接近, 但是不完美. 因为实际当中一个模具可以做出多个产品, 一个产品只有一个模具. 但编程语言当中不同, 由于类之间可以继承以及多继承, 也就是说一个对象可以对应多个类. 所以这个比喻不是特别合适, 但是类和对象的关系是没错的.
但是这就有了一个问题, 既然 Python 当中一切都是对象, 那么是不是说类其实也是一个对象呢? 也就是说一个模具其实也是另外一个模具的产品? 同样, 这个模具的模具其实也是另外一个模具的产品, 那么我们一直追问下去会怎么样呢?
很简单, 我们做个实验就知道了, 我们可以用_class__关键字来查看一个变量的类型, 那么我们反复调用就可以查看其中的关系了:
从上面的图中我们可以发现, num 是 int 类型的变量. 我们继续查看 int 这个类型的类型, 得到了 type 类型. 而当我们去查看 type 的类型的时候, 会发现我们得到的还是一个 type 的类型.
所以我们可以明白了, type 是 Python 中用来创建所有类的元类, 是所有模具的模具. 在 Python 当中, 我们把一个类的类叫做元类 (metaclass). 所以 type 就是 Python 当中内置的元类, 我们也可以自己创建我们需要的元类. 通过元类, 我们创建的对象也是一个类, 而不是一个实例.
动态创建类
理解了 type 是一切类基础之后, 再来看动态类就简单了. 动态类是动态语言最大的特性之一, 作为典型的动态语言, Python 自然也是支持类型的动态创建的.
在 Python 当中, 创建动态类型的一种方式就是通过 type 关键字. 说起来有些意想不到, type 函数不是用来查询对象所属的类型的吗, 怎么还可以创建类呢?
这其实是 type 的另外一种用法, 作为元类来创建一个类. 在这种用法, type 函数接收 3 个参数, 分别是类型的名称, 父类的元组, 以及一个字典. 除了第一个参数之外, 后面两个参数都可以为空. 比如我们来看一个例子:
注意, type 返回的结果是一个类, 而不是一个实例. 所以我们还可以通过它创建实例:
hello = Hello()
这样创建出来的是最简单的空类, 它什么也没有, 和下面的代码等价.
- class Hello:
- pass
我们也可以在 type 的参数当中为这个类填充属性和方法:
- def hello_world(self):
- print('hello')
- Hello = type('Hello', (), {'hello':hello_world, 'num': 3})
这样我们就为 Hello 这个类创建了一个方法叫做 hello, 一个属性 num 等于 3. 我们可以来调用一下试试:
也就是说我们可以使用 type 来根据我们的需要自行定义类, 只不过 type 既可以获取对象的类型又可以创建新的类, 看起来可能觉得有些不太直观, 但是其实这也是说得通的. 我们在 Python 当中通过调用 str 创建一个 string 对象, 通过 int 来创建一个 integer 对象, 那么通过 type 则是创建一个类的对象.
实现继承
我们之前说了, 当我们使用 type 来创建类的时候, 还可以传入父类的元组从而实现类的继承.
比如我们再创建一个叫做 World 的类继承刚才通过 type 创建出来的 Hello 类, 然后在为它加上额外的函数:
- def say_world(self):
- print('World')
- World = type('World', (Hello, ), {'world': say_world})
注意这里传入第二个参数是父类的元组, 既然是元组, 那么当元素只有一个的时候, 需要加上逗号, 表示这是一个元组. 这样创建出来的类和我们通过 class 定义的静态类效果是一样的:
也就是说, 我们可以先把函数实现, 然后再根据任务的需要把这些函数组装成新的类. 显然, 这和传统的 C++ 以及 Java 这些静态类型的语言相比, 要灵活得多.
总结
我们固然可以通过 type 来创建动态创建类, 但是从上面的使用过程也应该看得出来, 这样使用起来并不太方便, 并且很多进阶的功能很难实现. 举个简单的例子, 比如我们想要动态地为一个已有的类添加一些动态的方法, 生成新的类. 我们使用 type 就很难实现. type 也的确不是 Python 元类的主要运用, metaclass 才是王道, 但由于篇幅限制, 这部分将放在下一篇文章当中.
当然, 元类是一个非常高级的用法, 以至于 Python 的创始人说 99% 的 Python 程序员并不需要用到它. 所以如果你觉得理解起来非常费劲的话也没有关系, 知道这么个概念就可以了.
今天的内容就是这些, 如果喜欢本文, 可以的话, 请点个关注, 给我一点鼓励, 也方便获取更多文章.
来源: https://www.cnblogs.com/techflow/p/13048318.html