在了解元类的时候先了解一下储备的知识:
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)