在了解元类的时候先了解一下储备的知识:
exec 执行储存在字符串或文件中的 Python 语句,相比于 eval,exec可以执行更复杂的 Python 代码。
它的语法是:exec(object,globals,locals)
参数介绍(http://www.runoob.com/python3/python3-func-exec.html)
- object:必选参数,表示需要被指定的Python代码。它必须是字符串或code对象。如果object是一个字符串,该字符串会先被解析为一组Python语句,然后在执行(除非发生语法错误)。如果object是一个code对象,那么它只是被简单的执行。
- globals:可选参数,表示全局命名空间(存放全局变量),如果被提供,则必须是一个字典对象。
- locals:可选参数,表示当前局部命名空间(存放局部变量),如果被提供,可以是任何映射对象。如果该参数被忽略,那么它将会取与globals相同的值。
#代码一 code=''' global x x=0 y=2 ''' globals_dic={'x':10000} locals_dic={} exec(code,globals_dic,locals_dic) print(globals_dic) print(locals_dic) #代码二 code=''' x=1 y=2 def f1(self,a,b): pass ''' locals_dic={} exec(code,{},locals_dic) print(locals_dic)
我们平常定义一个类是这样子的。用class定义的类使用的类使用产生我们自己的对象的
class Chinese: country='china' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def speak(self): print('%s speak Chinese'%self.name) p=Chinese('MONICX',23,'male') print(type(p))#<class '__main__.Chinese'> print(type(Chinese))#<class 'type'>
元类,就是类的类。
python内置元类type是用来专门产生class定义的类
what:类名,bases:基类,dict:类体代码。
我们来看一下type是如何来定义一个类的。它的代码过程如下。
class_name='Chinese' class_base=(object,) class_body=''' country="china" def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def speak(self): print('%s speak Chinese'%self.name) ''' class_dic={} print(exec(class_body,{},class_dic)) Chinese=type(class_name,class_base,class_dic) print(Chinese)
通过上面的代码我们可以了解到内置元类type得到一个类的底层原理。
那么我们如何自定义一个元类呢!!!!!
自定义元类的储备知识:
# __call__ class Foo: #产生对象执行 def __init__(self): pass #打印对象执行 def __str__(self): pass #回收对象执行 def __del__(self): pass #调用对象时执行 def __call__(self, *args, **kwargs): print('__cal__')#__cal__ print('__cal__',args,kwargs)#__cal__ (1, 2, 3) {'m': 1} obj=Foo() obj(1,2,3,m=1)
内置元类type内部一定有一个__call__方法,我们自定义一个元类的时候,也要定义一个__call__方法。
我们来看一下自定义元类的实现过程。
class Mymeta(type): #控制类的创建 def __init__(self,class_name,class_base,class_dic): # print(class_name)#Foo # print(class_base)#(<class 'object'>,) # print(class_dic)#{'__module__': '__main__', '__qualname__': 'Foo', 'x': 1, '__init__': # <function Foo.__init__ at 0x0000000001E8A950>, 'f1': <function Foo.f1 at 0x0000000001E8A9D8>} if not class_name.istitle(): raise TypeError('类名的首字母必须大写!') if not class_dic.get('__doc__'): raise TypeError('类中必须写好文档注释,') #控制类Foo的调用,即控制实例化Foo的过程 def __call__(self, *args, **kwargs):#self=Foo args=(111, # print('=======>') # print(args) # print(kwargs) #1、造一个Foo的空对象 obj=object.__new__(self)#固定代码一 #2、调用Foo.__init__ #3、将obj连同调用Foo括号内的参数一同传给__init__ self.__init__(obj,*args,**kwargs)#固定代码二 return obj #Foo=Mymeta('Foo',(object),class_dic) class Foo(object,metaclass=Mymeta): ''' 文档注释 ''' x=1 def __init__(self,y): self.y=y def f1(self): print('form f1') # obj=Foo()#调用类会产生一个空对象。 # print(obj) obj=Foo(1111)#Foo.__call__() print(obj.y) print(obj.f1) print(obj.x)