一、eval、exec内置函数
1、eval函数
eval内置函数的使用场景:
①执行字符串会得到相应的执行结果
②一般用于类型转换得到dict、list、tuple等
2、exec函数
exec应用场景 用来辅助了解元类的概念
①执行字符串没有执行结果(没有返回值)
②将执行的字符串中产生的名字形成对应的局部名称空间
# 解析exec函数
# exec函数帮我们运行字符串中的代码,把字符串中产生的名字放到名称空间里
# 自己定义全局作用域中的名字和字典,自己定义局部作用域的名字和字典
# 将所要执行的代码放到字符串中,在字符串中写好操作全局作用域的和局部作用域的
# 字符串内放一堆代码,exec来运行字符串中的代码的时候产生的名字都会放到名称空间里,
# 放到自己定义的全局或者是局部的名称空间里,如果声明是global,就会放到global的字典里
# exec(字符串,global_dic, local_dic)
code = """ global x x=0 y=2 """ global_dic = {'x': 100000} local_dic = {} exec(code, global_dic, local_dic) print(global_dic) print(local_dic) # {'y': 2} code = """ x=1 y=2 def f1(self,a,b): pass """ local_dic = {} exec(code, {}, local_dic) print(local_dic) # {'x': 1, 'y': 2, 'f1': <function f1 at 0x00000000027A8C80>}
二、类的名称空间的控制
三、元类
1、定义:
python中万物皆对象,所有用来创建对象的类,本身也是对象,类是type类的对象
type类叫做元类,是所有元类的基类
元类:制造类的类 --类的类
-- 控制类的产生
-- 控制类的对象的产生
class CountError(Exception): pass class MyMeta(type): # 自定义元类,重写init方法的目的: # 1.该方法是从type中继承来的,所以参数同type的init # 2.最终的工作(如果开辟空间,如果操作内存)还是要借助type # 3.在交给type最终完成工作之前,可以对类的创建加以限制 ***** def __init__(cls, class_name: str, bases, namespace): print(cls) # <class '__main__.Student'> print(class_name) # Student print(bases) # (<class 'object'>,) print(namespace) # {'__module__': '__main__', '__qualname__': 'Student', '__init__': <function Student.__init__ at 0x0000000001EA89D8>} # 需求:由给元类控制的类的类名必须首字母大写 if not class_name.istitle(): raise NameError('名字首字母必须大写') # 需求:定义类是必须明确父类 if len(bases) == 0: raise CountError('父类必须明确') # super(MyMeta, cls).__init__(class_name, bases, namespace) super().__init__(class_name, bases, namespace) # 自定义元类,重写call方法的目的: # 1.被该元类控制的类生成对象,会调用元类的call方法 # 2.在call中的返回值就是创建的对象 # 3.在call中 # -- 通过object开辟空间产生对象 # -- 用被控制的类回调到自己的init方法完成名称空间的赋值 # -- 将修饰好的对象反馈给外界 def __call__(cls, *args, **kwargs): print('call fn run') # call fn run obj = object.__new__(cls) # 需求:所有通过该元类控制的类产生的对象都有meta_name该属性 obj.meta_name = cls.__name__ # obj.name = args[0] # 调回当前被控制的类自身的init方法,完成名称空间的赋值 cls.__init__(obj, *args, **kwargs) return obj # Student = MyMeta(class_name, bases, namespace) class Student(object, metaclass=MyMeta): def __init__(self, name, age): print('init fn run') # init fn run self.name = name self.age = age pass # stu = Student() # class Teacher(Student, metaclass=MyMeta): # pass stu = Student('Bob', 18) print(stu, stu.name, stu.age) # <__main__.Student object at 0x0000000001EB7FD0> Bob 18 stu = Student('Tom', 20) print(stu.meta_name) # Student
四、单例
1、定义:一个类只能产生一个实例
2、为什么要有单例:
①该类需要对象的产生
②对象一旦产生,在任何位置再实例化对象,只能得到第一次实例化出来的对象
3、单例实现的四种方法:
# 方法1 class Songs(): __instance = None @classmethod def getInstance(cls): # 对象没有创建返回,有直接返回 if cls.__instance == None: cls.__instance = cls() return cls.__instance # 约定别用 类名() 来实例化对象,用类方法来获取唯一对象 s1 = Songs() s2 = Songs() print(s1) # <__main__.Songs object at 0x0000000001E776D8> print(s2) # <__main__.Songs object at 0x0000000001E77710> print(s1 is s2) # False s1 = Songs.getInstance() s2 = Songs.getInstance() print(s1) # <__main__.Songs object at 0x00000000027A76D8> print(s2) # <__main__.Songs object at 0x00000000027A76D8> print(s1 is s2) # True # 方法2 ''' class Songs: # 类一旦重写__new__方法,该类的实例化有__new__来控制 # def __init__(self): # print('init') # def __new__(cls, *args, **kwargs): # print(args) # print(kwargs) # print('new') # pass pass s1 = Songs(1, 2) s2 = Songs(3, 4) print(s1, s2) ''' class Songs: __instance = None def __new__(cls, song_name, *args, **kwargs): if cls.__instance == None: cls.__instance = object.__new__(cls) cls.__instance.song_name = song_name return cls.__instance def change_song(self, song_name): self.song_name = song_name s1 = Songs('菊花爆满山') s2 = Songs('感觉身体被掏空') print(s1.song_name, s2.song_name) # 菊花爆满山 菊花爆满山 s2.change_song('感觉身体被掏空') print(s1.song_name, s2.song_name) # 感觉身体被掏空 感觉身体被掏空 # 方法3:采用装饰器 def outer(cls): _instance = None def inner(*args, **kwargs): nonlocal _instance if _instance == None: _instance = cls(*args, **kwargs) return _instance return inner @outer # Songs = outer(Songs) class Songs: pass s1 = Songs() s2 = Songs() print(s1) # <__main__.Songs object at 0x0000000001EB7748> print(s2) # <__main__.Songs object at 0x0000000001EB7748> print(s1 is s2) # True # 方法4 class SingleMeta(type): __instance = None def __call__(cls, *args, **kwargs): if SingleMeta.__instance == None: SingleMeta.__instance = object.__new__(cls) cls.__init__(SingleMeta.__instance, *args, **kwargs) return SingleMeta.__instance class Songs(metaclass=SingleMeta): def __init__(self): pass pass s1 = Songs() s2 = Songs() print(s1) # <__main__.Songs object at 0x0000000001E775C0> print(s2) # <__main__.Songs object at 0x0000000001E775C0> print(s1 is s2) # True