exec 模块的补充
exec是python 的一个内置模块
exec的作用
x = 10
def func():
pass
# 可以把"字符串形式" 的python代码, 添加到全局空间或局部名称空间中.
用法:
参数一: 字符串形式的python代码
参数二: 全局名称空间字典
参数三: 局部名称空间字典
调用exec()
# 全局名称空间
# # 1.文本形式的python代码
code = '''
global x
x = 10
y = 20
'''
# 2.全名的名称空间 {}
global_dict = {'x': 200}
# 3.局部名称空间 {}
local_dict = {}
exec(code, global_dict, local_dict)
print(global_dict)
# 局部名称空间
# 1.文本形式的python代码
code = '''
x = 100
y = 200
def func():
pass
'''
# 2.全名的名称空间 {}
global_dict = {}
# 3.局部名称空间 {}
local_dict = {}
exec(code, global_dict, local_dict)
# print(global_dict)
print(local_dict)
元类
什么是元类
元类就是类的类,Chinese类的类就是type,type是所有类的类,type就是元类
元类的作用
元类可以帮助我们控制类的创建
怎么自定义创建一个元类:
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
# metaclass ---> 自定义的元类
# 因为Foo类继承了元类,必须手动继承object
class Foo(Bar, metaclass=MyMeta): # MyMeta(Foo, Foo_name, (Bar, ), foo_dict)
'''
这是一个Foo类
'''
# 摊开坦克
x = 10
def __init__(self, y, z):
self.y = y
self.z = z
def f1(self):
print('from Foo.f1...')
foo = Foo(20, 30) # 调用Foo对象,会触发__call__
优酷框架
-
ATM
-
用户试图层
-
接口层
-
数据层
-
dict
-
json
优点: 数据可以跨平台
缺点: 不能存对象,也不能直接获取对象.
不能通过"对象.属性" 的方式存,取值
-
-
-
选课系统
-
用户视图层
-
接口处
-
数据层
- models
- obj
- pickle
优点: 可以通过"对象.属性" 的方式存,取值
缺点: 不能跨平台 - models
-
-
优酷
- 用户视图层
- 接口层
- 数据层
- 存储对象 ---> dict ---> Json ---> MySQL
- MySQL ---> Json ---> dict ---> 获取对象
ORM
ORM: 对象关系映射 ---> 映射到数据库MySQL中的数据表
类名 ---> 表名
对象 ---> 一条记录
对象.属性 ---> 字段
模拟Django的ORM, 为了,将数据库的增,删,改,查全部封装成一个个的方式, 比如: save, delete, update, select.
创建字段的类型,对应数据表的一个个字段的创建规范
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=Flase,default=None):
super().__init__(name,column_type,primary_key,default)
#class Father:
# def __inti__(self.*arg,**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 = IntegerFild(name='user id')
user_name = StringField(name='name')
pwd = StringField(name='pwd')
class Movie(Models):
pass
user = User(id='007',name='tank',pwd='123') # ---> 一条记录
# print(user)
# print(type(user))
movie = Movie(m_id='1',movie_name='json真实写真')
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__)
问题1: 解决代码冗余的问题,比如有100张表,需要写100次__initial__
解决1: 继承一个父类,父类中定义一个 __init__
问题2: 无法预测每一张表中的字段是什么,无法通过父类的__init__解决问题.
解决2: 通过继承字典,内部的_init_,可以接受"任意个数" 的关键字参数
问题3: 继承字典的类实例化的对象,无法通过"对象.属性" 的方式存取值
解决3: 通过__setattr__, __getattr__来实现,让字典对象与普通对象一模一样,并且具备字典原有的特性.
元类需要处理的问题:
1. 给数据表类,强制必须要有一个主键
2. 逐渐必须是唯一的
user_obj = User(user_id = 1,user_name = 'tank',age = 18)
# insert into User(name,age) values('tank',18);
user_obj,save()
list1 = []
obj.save() # obj.table_name
sql = "insert into Movie(name,age,3,4,5...) values('tank',18,3,4,5...)"
# insert into obj.table_name(name,age,3,4,5...) values('tank',18,3,4,5...);
创建字段的类型,对应数据表中的一个个字段的创建规范
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().__inti__(name,column_type,primtary_key,default)
元类需要处理的问题
1. 一张表必须要有一个表名
2. 给数据表类,强制必须要有一个主键,主键必须是唯一的
3. 将数据表中,所有的字段对象,都存在一个独立的字典中
class OrmMtaClass(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 int 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 int 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 __serattr__(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')
# 用户表
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')
if __name__ == '__main__':
print(User.__dict__)