一、exec模块的补充
python的内置模块,可以把“字符串形式”的python代码,添加到全局名称空间或局部名称空间中
# 1. 对全局名称空间中的值进行修改
## 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)
# 2. 局部名称空间
## 1. 文本形式的python代码
code = '''
x=100
y=200
def func():
pass
'''
## 2. 全局名称空间 {}
global_dict={'x':200}
## 3. 局部名称空间 {}
local_dict={}
exec(code,global_dict,local_dict)
print(local_dict)
二、元类
(一)什么是元类
- python中一切皆对象,而类本质上也是另一个类实例化出来的对象,而这个类就叫做元类(简称类的类),内置的元类为type
- 元类可以控制类的创建
(二)通过class关键字创建类
class创建类时,内部会自动调用元类type,type会帮我们创建一个自定义类,此时会传入三个参数:
- 类名class_name
- class_bases = (object,)
- 类的名称空间class_dic,由执行类体代码得到的
(三)自定义元类控制类的创建
- 自定义创建元类:
- 自定义一个元类,继承type,派生出自己的属性和方法
- 通过metaclass指定自定义好的元类,来控制类的创建
- 通过元类type创建类,会在调用的时候(
__call__
)做三件事:- 产生一个空对象
- 调用
__init__
方法初始化对象obj - 返回初始化好的obj
class MyMeta(type):
# 控制对象的创建
# def __new__(cls,class_name,class_base,class_dic)
# 控制类的定义
def __init__(self,class_name,class_base,class_dic):
# 判断首字母是否大写
if not class_name.istitle():
raise TypeError ('类的首字母必须大写')
# 控制类中必须要有注释
if not class_dic.get('__doc__'):
raise TypeError('类内部必须要写注释')
# 模拟type元类内部做的事情
def __call__(self,*args,**kwargs):
# 1. 调用__new__创建一个空对象
obj = object.__new__(self)
# 2. 执行__init__(self,*args,**kwargs)
obj.__init__(*args,**kwargs)
return obj
class Foo(object,metaclass=MyMeta):
'''注释'''
x= 10
def __init__(self,a,b):
self.a = a
self.b = b
def f1(self):
print('f1')
foo = Foo(10,20) # 调用Foo对象,会触发__call__
print(foo.b)
三、ORM
ORM:对象关系映射,将类和数据库中的数据表进行映射
类名对应表名,对象对应记录,属性对应字段
这样可以通过对象.属性的方法直接访问到表数据,将数据库的增删改查全部封装成一个个函数
# 1. 字段类
## 1. 父类
class Field:
def __init__(self,name,type,primary_key,default):
self.name= name
self.type = type
self.primary_key = primary_key
self.default= default
## 2. 整形类
class Integer(Field):
def __init__(self,name,type='int',primary_key=False,default=0):
super().__init__(name,type,primary_key,default)
## 3. 字符串类
class String(Field):
def __init__(self,name,type='varchar',primary_key=False,default=None):
super().__init__(name,type,primary_key,default)
# 2. 元类
class OrmMetaClass(type):
def __new__(cls, class_name,class_bases,class_dic):
# 1. Models不用做判断,剔除掉Models类,
if class_name=='Models':
return type.__new__(cls,class_name,class_bases,class_dic)
# 2. 表名、主键、存储字段对象
table_name = class_dic.get('table_name',class_name) # 如果没有表名,类名做表名
primary_key = None
mappings = {} # 存储字段对象,防止,表记录对象.属性时触发不了__getattr__
# 3. 判断是否是唯一主键和必须要有主键,同时筛选出字段对象
for k,v in class_dic.items():
if isinstance(v,Field): # 判断是否是字段对象
mappings[k] = v # k是字段名,v是字段对象,v.name=k
if v.primary_key: # 如果字段对象中主键为真
if primary_key: # 默认primary_key为空,如果成立,说明,有两个主键
raise TypeError('只能有一个主键')
primary_key = k # k = v.name
# 4. 将类的内存空间中的的字段对象剔除,防止触发不了__getattr__,同时节省内存
for k in mappings.keys():
class_dic.pop(k)
# 5. 如果此时primary_key为空,说明没有主键
if not primary_key:
raise TypeError('必须要有一个主键')
# 6. 将主键名,表名,存储字段对象的字典存入类的名称空间
class_dic['table_name'] = table_name
class_dic['primary_key'] = primary_key
class_dic['mappings'] = mappings
# 7. 将修改好的名称空间,返回出去给__init__
return type.__new__(cls,class_name,class_bases,class_dic)
# 3. 表名父类
class Models(dict,metaclass=OrmMetaClass):
# 1. 对象.属性没有触发,返回字典取值,模仿对象中的属性
def __getattr__(self, item):
return self.get(item)
# 2. 对象.属性=赋值时触发,返回字典增加值,方便后续存储
def __setattr__(self, key, value):
self[key] = value
# 4. 用户表类
class User(Models): # 继承的dict,不需要设置__init__
user_id = Integer(name = 'user_id',primary_key=True)
user_name= String(name='user_name')
pwd = String(name='pwd')
u = User(user_id=1,user_name='wick',pwd='123')
print(u.user_id,u.user_name,u.pwd)