本篇简单记录一些关于Python如何利用元类、monkey patch以及类装饰器来动态修改类的知识。
Python元类
基本观点
这些观点主要来自What are metaclasses in Python?:
type是Python的内建元类;
__metaclass__实际上可以被任意调用,它并不需要是一个正式的类;
当使用class关键字时,Python解释器自动创建类对象;
如果不希望自动创建,可以采用type,type能动态的创建类。它接受类的描述作为参数,然后返回一个类;
创建类会经历的查找过程:编写的类中查找有__metaclass__,没有就继续在父类找,没有就在模块层次找,最终都没找到,就用内置的type创建类对象;
__metaclass__可以放置type,或者任何使用到type或者子类化type的东东都可以;
元类的主要目的就是为了创建类时能够自动地改变类,具体实现为:(1)拦截类的创建,(2)修改类,(3)返回修改后的类;
__new 是在init__之前被调用的特殊方法;
__new__是用来创建对象并返回之的方法;
\而init只是用来将传入的参数初始化给对象;
type.__new__创建type对象并返回;
代码实践
type创建类对象的基本格式:type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
下面是一个元编程的例子:
|
|
__metaclass__所处的位置不影响构建类对象;
monkey patch
monkey patch:概念上类似于Java里面的热修复,主要作用是在不更改源代码的情况下,动态追加和变更类的功能;
一个简单的例子:
|
|
eat方法在运行时成功替换成common_eat方法。
类装饰器
首先明确functools包下的wraps,它可以使函数在调用name和doc属性时,打印被装饰的函数的信息,而非装饰函数的信息。
写一个类装饰器的例子,下面是写法一:
|
|
route参数只有一个且就是被装饰的函数时(这里指不包含self),可以直接不写括号;
在看另一种写法:
|
|
这里的route设定的是要传入一个str参数,在书写装饰器时显式给出,在构造装饰器逻辑的时候,嵌套的方法wrapper被返回的是func函数对象而不是函数运算求得的值,所以只是函数的引用改变了,那么打印函数的doc仍是原函数的内容;
类装饰器有一个好处是装饰的逻辑可以通过类继承,这样能方便程序的扩展;