Python 元编程编译器工作流程
Python 元编程探究,如果你不了解元编程请不要使用,复杂的东西只应该用在复杂的环境下。
if __name__=='__main__':
print 'what?'
class Mytype(type):
def __new__(cls, name, bases, attrs):
print cls,'new in Mytype'
return super(Mytype,cls).__new__(cls, name, bases, attrs)
def __call__(cls,*a,**d):
print cls,'call in Mytype'
print cls,a,d
return super(Mytype,cls).__call__(*a,**d)
def __init__(cls,*a,**d):
print 'init in Mytype'
return super(Mytype,cls).__init__(*a,**d)
class Mytype2(Mytype):
def __new__(cls, name, bases, attrs):
print cls,'new in Mytype2'
return super(Mytype2,cls).__new__(cls, name, bases, attrs)
def __call__(cls,*a,**d):
print cls,'call in Mytype2'
print cls,a,d
return super(Mytype2,cls).__call__(*a,**d)
def __init__(cls,*a,**d):
print 'init in Mytype2'
return super(Mytype2,cls).__init__(*a,**d)
__metaclass__=Mytype
print 'Ins'
class Ins(object):
__metaclass__=Mytype2
def __new__(cls,*a,**d):
print cls,'new in Ins'
return super(Ins,cls).__new__(cls,*a,**d)
def __call__(self,*a,**d):
print 'call in Ins'
return super(Ins,self).__call__(*a,**d)
def __init__(self,*a,**d):
print 'init in Ins'
return super(Ins,self).__init__(*a,**d)
print 'Ins2'
class Ins2(Ins):
__metaclass__=Mytype
def __new__(cls,*a,**d):
print 'new in Ins2'
return super(Ins2,cls).__new__(cls,*a,**d)
def __call__(self,*a,**d):
print 'call in Ins2'
return super(Ins2,self).__call__(*a,**d)
def __init__(self,*a,**d):
print 'init in Ins2'
return super(Ins2,self).__init__(*a,**d)
print 'Ins3'
class Ins3():
pass
print __name__
A,import
当使用(1)from xx import xx或直接(2)import xx或直接使用(3)python xx.py运行脚本的时候,编译器开始读取文件加载初始化文件中class,执行相关函数调用。1,2,3的区别在与使用3时,编译器所自带的全局变量__name__被更正为__main__而不是源文件名,这一切都是顺序的。
B, 使用metaclass初始化class
在这里咱不扯对象这个概念,以免将自己绕晕,就一条,源代码中的class需要实例化(分配内存),metaclass就不用了,怎么区别她两呢?class指父类没有metaclass的定义,metaclass是指父类只有metaclass的定义,python内置metaclass就是type。
那要是我定义一个class继承了metaclass又继承了普通class算什么呢?编译器会告诉你算出错!
所以你可以这么写:
class A():
pass
class B(object):
pass
class C(type):
pass
class D(A,B):
pass
class E(C):
pass
但是你不可以这么写:
class Fuck(D,E):
pass
还没有进入正题,下面继续说。
每一个class都有且仅有一个metaclass相伴,如果你没有显式的定义,编译器使用type来实例化,如果你定义了,编译器按照你的逻辑来。你可以在三个地方声明class的metaclass,(1)全局变量__metaclass__,(2)类变量__metaclass__,(3)通过父类继承而来。
有且仅有一个metaclass是指,你可以这么写:
class G(C):
pass
class G(C):
__metaclass__=E
但你不可以这么写
class Fuck(type):
pass
class G(C):
__metaclass__=Fuck
这三个地方的优先级是(2>3>1),当有2或3时,编译不再搭理1,编译器目的只有一个,在new阶段(即__new__接口调用)确定class的metaclass伴侣。
首先调用2的new,接下来调用3的new,最终选取的metaclass一定是最上层的(如果C和E同时入选,E被选中),所以在遇见低层次的metaclass时,编译器同样选择不搭理。
例如2中写C,3中写E,调用顺序是
([2]C.\__new__)->([3]E.\__new__->C.\__new__)
2中写E,3中写C,调用顺序是
([2]E.\__new__->C.\__new__)
ok,我们在new中完成了class的实例化,如果你错过了,还有一次机会,选定了metaclass之后接下来编译器会调用metaclass的__init__接口。
C,使用class生成一个instance
接下来没什么复杂的了,class和 metaclass的关系已经确定,编译器的调用顺序为:
首先调用metaclass的call,假如metaclass是E,顺序是E.__call__->C.__call__
最后调用class自身的new接口返回instance,至此我们完整的生成了平常称呼的对象。
最后罗嗦一句,new接口的调用需要手动传入调用者, 除此之外python都会自动传入调用者作为第一参数。
感谢你看完这么长段技术文章。
print type('I',(object,),{'said':'thank you!'})().said