简要介绍python的元编程的metaclass

具体请点击:http://www.verydemo.com/demo_c122_i20324.html

平时经常看到元编程、DSL这样的字眼,它到底是什么意思?
我的理解来看。元编程就是“代码生成器”,你可以通过一些代码生成另一些代码(动态地、按需的)。DSL则是domain special language:为了解决某个问题而发明的语言,比如HTML SQL YACC,它的反面是C JAVA Python这些通用语言。与DSL经常提到的是ruby,为什么说ruby可以DSL呢?因为它语法丰富,支持各种简写,lamba,闭包,block等等,通过自定义的一套高级API从而实现一门特定领域的方言。这种方言是可以交给客户写的。


python中元编程的目标是:动态生成需要的类class。我们知道class实例化后就是instance,而python中的metaclass实例化后就是class了。先看一个例子
class MyMeta(type):  
    def __new__(cls, name, parents, attrs):
        print("new info: ", cls, name, parents, attrs)
        attrs['abcde'] = 'fghijk'
        return type.__new__(cls, name, parents, attrs)

class C(metaclass=MyMeta):
    pass

print(C.abcde)

输出结果是:
引用
fghijk

通过修改__new__里面的attrs就可以更改类的属性

python类在初始化的时候,经历了两个阶段,第一个阶段是分配空间__new__(),第二个阶段是初始化值__init__()。当类被创建时,python2会首先寻找__metaclass__是否存在,如果存在则调用__metaclass__。如果此类没定义__metaclass__就去看父类,父类没有就去模块里找(全局变量__metaclass__),包里再没有就把__metaclass__ = type作为类的metaclass。而python3先看自己metaclass有没有定义,如果没有就看父类,父类没有就用type

再介绍下__new__中各个参数的意思:cls代表调用__new__函数的class,name代表对象的__name__值,也就是名称,parents代表对象的父类元组,attrs代表类的属性字典。

metaclass功能就是这么简单,一般来说是用不上的,除非要大批量的修改类的属性。其实python本身就是动态语言,在运行时就可以更改属性。而且decorator也可以很好的修改调用对象前后的行为。所以metaclass了解就行。

metaclass还有一些比较边边角角的知识点,比如说MyMeta这里还会引入一个__prepare__函数:
#官方文档说要是classmethod类型
    @classmethod
    def __prepare__(self, *args, **kwargs):
        print("__prepare__ called")
#        return type.__prepare__(self, *args, **kwargs)
        return kwargs

这个函数还要在__new__函数调用之前调用,这个函数必须返回一个用于存放类属性(namespace)的数据结构,默认情况下就是字典类型了。我在这里直接就把kwargs返回就可以,没问题的,极端点,return {}都是可以的。这里可以玩一下,比如说
return {'xx': 'yy'}

你会发现整个类中都会被添加xx这个属性……

最后附上几个小知识点:
#可以使用type动态创建一个类
myclass = type("MyClass", (), {})
print(myclass)
s = super(myclass, myclass())
#super其实返回一个super object
print(s)
#输出结果是:
<super: <class 'MyClass'>, <MyClass object>>

相关推荐