exec 补充
exec 模块的补充
1.exec是什么?
exec 是一个python内置模块。
2.exec 的作用;
可以把"字符串形式"的python代码,添加到全局空间或局部空间中。
""" x = 10 def func1(): pass """
3.怎么用:
参数1:字符串形式的python代码
参数2:全局名称空间字典
参数3:局部名称空间字典
调用exec()
代码:
# 全局名称空间 # # 1.文本形式的python代码 code = ''' global x x = 10 y = 20 ''' #2.全局的名称空间{} globals_dict = {'x':200} # 3.局部名称空间{} locals_dict = {} exec(code,globals_dict,locals_dict) # 用exec 不仅打印全局的代码,还打打印了内置的代码。 print(globals_dict) 局部名称空间{} code = ''' global x x = 100 y = 200 def func(): pass ''' #2.全局的名称空间{} globals_dict = {} # 3.局部名称空间{} locals_dict = {} exec(code,globals_dict,locals_dict) # 用exec 不仅打印的代码,还打打印了内置的代码。 print(globals_dict)
元类
在 python中,一切接是对象。
"""
创建类有两种方法:
1.通过class关键之创建类,内部会自动调用type(), type 帮我们创建一个自定义类
2.通过手动调用type()实列化得到自定义的类。
"""
# what: 类名 --> type对象的名称 # bases: --> 基类/父类 # dict: --> 类的名称空间 手动调用:(通过class关键字创建的) 建议以后多使用此方法。 class Chinses: country = 'China' def __init__(self,name,age): self.name = name self.age =age def speak(self): print('speak chinese....') p1 = Chinses('tank',18)# 自动调用 print(Chinese) 结果: <class '__main__.Chinses'> 自动调用 (通过type手动创建的) class_name = 'Chinese' class_base = (object,) class_dict = {} code = ''' country = "China" def __init__(self,name,age): self.name = name self.age = age def speak(self): print("speak Chinese...") ''' exec(code,{},class_dict) Chinses = type(class_name,class_base,class_dict) print(Chinses) 结果: <class '__main__.Chinses'>
1.什么是元类?
元类就是类的类,Chinese类的类是type,type是所有类的类,type就是一个元类。
2.元类的作用?
元类可以帮我们控制类的创建。
元类可以帮我们控制类的创建。
3.怎么自定义创建元类:
1) 自定义一个元类,继承type,派生出自己的属性与方法。
2) 给需要使用的类,通过metaclass指定自定义好的元类。class Chinese(metaclass='自定义的元类'):'''
# 自定义元类 class MyMeta(type): # 子类的方法与父类的方法一样,先用子类的,子类覆盖父类的__init__方法。 # 控制了类的定义 def __init__(self, class_name, class_base, class_dict): # print(class_name) # 判断字符串首字母是否大写 if not class_name.istitle(): raise TypeError('类的首字母必须大写!') # 控制类中必须要有注释 if not class_dict.get('__doc__'): raise TypeError('类内部必须要写注释!') # print(class_base) # print(class_dict) super().__init__(class_name, class_base, class_dict) # 模拟type元类内部做的事情 # 元类触发的__call__可以控制类的调用。调用__call__会触发以下两点 def __call__(self, *args, **kwargs): # 1.会调用__new__()--> obj, 会创建一个空对象。 obj = object.__new__(self) # 2.会执行__init__(obj, *args, **kwargs), obj.__init__(*args, **kwargs) return obj # 可以通过元类内部的__new__控制对象的创建 def __new__(cls, *args, **kwargs): pass class Bar: pass
优酷构架
ATM
用户试图层
接口层
数据层
dict
json
优点:数据可以跨平台。
缺点:不能存在对象,也不能直接获取对象。 {.......}
不能通过"对象.属性"的方式 存 取值。
存储速度比pickle慢。
选课系统
用户试图层
接口层
数据层
models:
obj
pickle
优点:可以通过对象''属性''的方式 存 取值。
能存对象,也能直接获取对象。
pickle
缺点:不能跨平台。
优酷
用户试图层
接口层
数据层
存储对象 --》 dict ---》json ---》mysql
mysql ----》 json ----》dict ----》 获取对象
ORM
ORM:
ORM:对象关系映射 ---> 映射到数据库MySQL中的数据表
类名 ---> 表名
对象 ---> 一条记录
对象.属性 ---> 字段
模拟Django的ORM,为了,将数据库的 增、删、改、查,全部封装成一个个的方式,比如: save, delete, update, select。
1.创建字段的类型,将数据库的 增,删,改,查,全部封装。
# 1.创建字段的类型, 对应数据表中的一个个字段的创建规范 class Field: def __init__(self, name, column_type, primary_key, default): self.name = name self.column_type = column_type self.primary_key = primary_key self.default = default # Integer class IntegerField(Field): def __init__(self, name, column_type='int', primary_key=False, default=0): super().__init__(name, column_type, primary_key, default) # String class StringField(Field): def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None): super().__init__(name, column_type, primary_key, default) class Father: def __init__(self, *args, **kwargs): self.id = id self.username = args[0] self.password = args[1] self.photo = args[2] class Models(dict): # 会在 对象.属性 没有时 触发 def __getattr__(self, item): print(item, '调用没有的属性时会触发...') # 将字典中key对应的值,返回给对象 return self.get(item) # dict_obj.get(key) # 在 对象.属性=值 时触发 def __setattr__(self, key, value): print(key, value) # 给字典对象本身赋值 self[key] = value # 创建数据表类 # 用户表类 class User(Models): # ---> 表名 # 强调: 最好与字段类型的name属性同名 user_id = IntegerField(name='user_id') user_name = StringField(name='name') # tank pwd = StringField(name='pwd') # 123 pass # 电影表类 class Movie(Models): pass user = User(id='007', name='tank', pwd='123') # ---> 一条记录 # print(user) # print(type(user)) movie = Movie(m_id='1', movie_name='jason真实写真') print(movie) print(type(movie)) # 字典的取、存值方式 print(user['id']) user['age'] = 18 print(user.get('id')) print(user.get('age')) user.age = 18 # {key: value} print(user.age) user.sex = 'male' print(user.sex) # None ---> return self.get(sex) --> 'male' print(user['sex']) # male print(user.__dict__) # 结果: {'m_id': '1', 'movie_name': 'jason真实写真'} <class '__main__.Movie'> 007 007 18 age 18 age 调用没有的属性时会触发... 18 sex male sex 调用没有的属性时会触发... male male {} ''' 问题1: 解决代码荣誉问题,比如有100张表,需要写100次__init__。 解决1: 继承一个父类,父类中定义一个__init__。 问题2: 无法预测每一张表中的字段是什么,无法通过父类的__init__解决问题。 解决2: 通过继承字典,内部的__init__, 可以接受“任意个数”的“关键字参数”。 问题3: 继承字典的类实例化的对象,无法通过“对象.属性”的方式存取值。 解决3: 通过__setattr__,__getattr__来实现,让字典对象与普通对象一模一样,并且具备字典原有的特性。 ''' 问题1: 解决代码荣誉问题,比如有100张表,需要写100次__init__。 解决1: 继承一个父类,父类中定义一个__init__。 问题2: 无法预测每一张表中的字段是什么,无法通过父类的__init__解决问题。 解决2: 通过继承字典,内部的__init__, 可以接受“任意个数”的“关键字参数”。 class Field: def __init__(self,name,colunm_type,primary_key ,default): self.name =name self.column_type = colunm_type self.primary_key = primary_key self.default = default class IntergerField(Field): def __init__(self,name,colunm_type='int',primary_key = False,default=0): super().__init__( name, colunm_type , primary_key, default) class StringField(Field): def __init__(self,name,colunm_type='varchar(64)',primary_key = False,default=None): super().__init__(name, colunm_type, primary_key, default) class User(dict): pass class Moive(dict): pass user = User(id = '007',name='tank',pwd = '123') print(user) print(type(user)) print(user['id'])# 只打印索引key的值 007 moive = Moive(m_id = '1',movie_name = 'tank真是写真') print(moive) print(type(moive)) print(user.get('id')) #只打印索引key的值 007 #结果: {'id': '007', 'name': 'tank', 'pwd': '123'} <class '__main__.User'> 007 {'m_id': '1', 'movie_name': 'tank真是写真'} <class '__main__.Moive'> 007
问题1: 解决代码荣誉问题,比如有100张表,需要写100次__init__。 解决1: 继承一个父类,父类中定义一个__init__。 问题2: 无法预测每一张表中的字段是什么,无法通过父类的__init__解决问题。 解决2: 通过继承字典,内部的__init__, 可以接受“任意个数”的“关键字参数”。 问题3: 继承字典的类实例化的对象,无法通过“对象.属性”的方式存取值。 解决3: 通过__setattr__,__getattr__来实现,让字典对象与普通对象一模一样,并且具备字典原有的特性。
# 1.创建字段的类型, 对应数据表中的一个个字段的创建规范 class Field: def __init__(self, name, column_type, primary_key, default): self.name = name self.column_type = column_type self.primary_key = primary_key self.default = default # Integer class IntegerField(Field): def __init__(self, name, column_type='int', primary_key=False, default=0): super().__init__(name, column_type, primary_key, default) # String class StringField(Field): def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None): super().__init__(name, column_type, primary_key, default) ''' 元类需要处理的问题: 1.一张表必须要有一个表名。 2.给数据表类,强制必须要有一个主键,主键必须是唯一的。 3.将数据表中,所有的字段对象,都存放在一个独立的字典中 存不是目的,目的是为了取值方便。 ''' class OrmMetaClass(type): # def __new__(cls, *args, **kwargs): # print(args, 'args............') # print(kwargs, 'kwargs........') # OrmMetaClass(class, class_name, class_base, class_dict) def __new__(cls, class_name, class_base, class_dict): # print(class_name, '类名--》表名') # print(class_base, '基类/父类') # print(class_dict, '类的名称空间') # 过滤Models类 if class_name == 'Models': # models类中,什么都不做,将类原路返回。 return type.__new__(cls, class_name, class_base, class_dict) # 1.一张表必须要有表名 # 假如table_name没有值,则将类名当做表名 table_name = class_dict.get('table_name', class_name) # get--> self.table_name # 2.主键名 primary_key = None # 3.定义一个空字典, 专门用来存放字段对象 mappings = {} # 遍历名称空间中所有的属性 for key, value in class_dict.items(): # print(key, value) # 除了有字段,还有其他字段以外的属性 # 过滤字段对象以外的内容 if isinstance(value, Field): mappings[key] = value # 判断字段对象primary_key是否为True if value.primary_key: # 先判断初识的primary_key是否有值 # 判断主键是否已存在 if primary_key: raise TypeError('只能有一个主键!') # 若主键不存在,则给primary_key赋值 primary_key = value.name # 节省资源: 因为mappings与原类中名称空间中的属性重复,为了节省内存,剔除重复的属性。 for key in mappings.keys(): class_dict.pop(key) # 判断是否有主键 if not primary_key: raise TypeError('必须有一个主键') # 给类的名称空间添加表名 class_dict['table_name'] = table_name # 给类的名称空间添加主键名 class_dict['primary_key'] = primary_key # 给类的名称空间添加一个mappings字典,字典中拥有所有字段属性 class_dict['mappings'] = mappings return type.__new__(cls, class_name, class_base, class_dict) class Models(dict, metaclass=OrmMetaClass): # OrmMetaClass(Models, Models_name, base, class_dict) def __getattr__(self, item): print(item, '调用没有的属性时会触发...') # 将字典的值,返回 return self.get(item) def __setattr__(self, key, value): print(key, value) self[key] = value # 用户表类 class User(Models): # ---> 表名 # table_name = 'user_info' # 强调: 最好与字段类型的name属性同名 user_id = IntegerField(name='user_id', primary_key=True) user_name = StringField(name='name') pwd = StringField(name='pwd') pass # 用户表类 class Movie(Models): # ---> 表名 # table_name = 'user_info' # 强调: 最好与字段类型的name属性同名 user_id = IntegerField(name='user_id', primary_key=True) user_name = StringField(name='name') pwd = StringField(name='pwd') pass if __name__ == '__main__': print(User.__dict__)
元类需要处理的问题: 1.一张表必须要有一个表名。 2.给数据表类,强制必须要有一个主键,主键必须是唯一的。 3.将数据表中,所有的字段对象,都存放在一个独立的字典中 存不是目的,目的是为了取值方便。
{'__module__': '__main__', 'table_name': 'User', 'primary_key': 'user_id', 'mappings': {'user_id': <__main__.IntegerField object at 0x0000020CD1F52508>, 'user_name': <__main__.StringField object at 0x0000020CD1F523C8>, 'pwd': <__main__.StringField object at 0x0000020CD1EF2AC8>}, '__doc__': None}