---恢复内容开始---
一、元类的介绍 元类:在python里,一切皆对象。所有自定义的类本身也是元类的对象,即所有自定义的类本质上也是由元类实例化出来的。 class关键字创建自定义类的底层的工作原理(分为四步) 1、先拿到类名 2、再拿到类的基类们 (object,) 3、接着拿到类的名称空间 4、调用元类实例化得到自定义的类 通过class关键字创建一个类 class text: def __init__(self,name,age): self.name=name self.age=age text1=text('jun',18) print(type(text)) #<class 'type'> 不依赖class自定义一个类: #1、拿到类名 class_name='text' #2、拿到类的基类 class_bases=(object,) #3、拿到类的名称空间 class_dic={} 补充exec的用法: class_body=''' class text: def __init__(self,name,age): self.name=name self.age=age ''' exec(class_body,{},class_dic) class_body是局部变量,{}是全局变量 class_dic是名称空间 print(class_dic) # {'text': <class 'text'>} #4、调用type得到自定义的类 temp=type(class_name,class_bases,class_dic) print(temp) #<class '__main__.text'>
二、自定义元类埃控制类的产生 类的产生: 1、文档必须使用驼峰体 2、类名中必须有文档注释,且文档注释不能为空 #上述为默契,也可以通过代码来达到这些要求 class Mymeta(type):#但凡继承type的类才能称为自定义的元类,否则就只是一个普通的类 def __init__(self,class_name,class_bases,class_dic): if class_name.islower(): raise TypeError('类名必须使用驼峰体') doc = class_dic.get('__doc__') if doc is None or len(doc) == 0 or len(doc.strip(' ')) == 0: raise TypeError('类体中必须有文档注释,且文档注释不能为空') print(self) #<class '__main__.Oldboy'> print(class_name) #Oldboy print(class_bases) #(<class 'object'>,) print(class_dic) #{'__module__': '__main__', '__qualname__': 'Oldboy', '__init__': <function oldboy.__init__ at 0x00000000021A1730>} class Oldboy(object,metaclass=Mymeta): #oldboy=Mymeta('oldboy',(object,),{}) ''' 必须存在文档注释 ''' def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex print(Oldboy) #<class '__main__.Oldboy'>
三、自定义元类控制类的调用过程 class Mymeta(type): pass class text(object): def __init__(self,name,age,sex): self.name=name self.age=age self.sex=sex def __call__(self, *args, **kwargs): print(self) print(args) print(kwargs) temp=text('jun',18,'male') temp(1,2,a=1,b=2) #==__call__(temp,(1,2),{'a':1,'b':2}) #对象的调用 #对象之所以可以调用,是因为对象的类中有一个函数 __call__ #推导:如果一切皆对象,那么text也是一个对象,该对象之所以可以调用, #是因为该对象的类中也定义了__call__ class Mymeta(type): def __call__(self, *args, **kwargs): #此处的self=text这个类 # 1、先产生一个空对象 obj=self.__new__(self) #obj是text这个类的对象
# 2、执行__init__方法,完成对象的初始化属性操作
self.__init__(obj,*args,**kwargs)
print(obj.__dict__) #{'name': 'jun', 'age': 18, 'sex': 'male'} 查找对象的字典
obj.__dict__={('_%s__%s'%(self.__name__,k)):v for k,v in obj.__dict__.items() }
#这一步可以做到私有化属性
print(obj.__dict__) #{'_text__name': 'jun', '_text__age': 18, '_text__sex': 'male'}
# 3、返回初始化好的那个对象
return obj
class text(object,metaclass=Mymeta):
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
temp=text('jun',18,'male') #会触发元类中的__call__函数
print(temp) #<__main__.text object at 0x0000000001DD9208>
#实例化
#1、先产生一个空对象
#2、执行__init__方法,完成对象的初始化属性操作
#3、返回初始化好的那个对象
补充:exec,eval # eval内置函数的使用场景: # 1.执行字符串会得到相应的执行结果 # 2.一般用于类型转化,得到dict、list、tuple等 dic_str = "{'a': 1, 'b': 2, 'c': 3}" res = (eval('dic_str')) # 得到原先的结果 res1 = (eval(dic_str)) # 得到字符串里面的类型 print(type(res), type(res1)) # <class 'str'> <class 'dict'> list_str = "[1, 2, 3, 4, 5]" print(list_str, type(list_str)) # [1, 2, 3, 4, 5] <class 'str'> print(type(eval(list_str))) # <class 'list'> with open('2.txt', 'r', encoding='utf-8') as rf: data_str = rf.read() print(data_str, type(data_str)) # [1, 2, 3, 4, 5] <class 'str'> import json # 文件里字典里的key的引号必须为双引号 res = json.loads(data_str) # 字符串转化为其他格式 print(res, type(res)) # [1, 2, 3, 4, 5] <class 'list'> data_str = "{'a': 1, 'b': 2, 'c': 3}" # 可以不考虑引号的种类,直接转换 res = eval(data_str) print(res, type(res)) # {'a': 1, 'b': 2, 'c': 3} <class 'dict'> # exec应用场景 # 1.执行字符串没有执行结果(没有返回值) # 2.将执行的字符串中产生的名字形成对应的局部名称空间 s = ''' my_a = 10 my_b = 20 def __init__(self): pass @classmethod def print_msg(msg): print(msg) ''' l_dic = {} exec(s, {}, l_dic) #s是局部变量,{}是全局变量,l_dic名称空间 print(l_dic) print(l_dic.items()) #{'name': 'Bob', 'age': 20}