(day38)元类+ORM
2024-10-20 08:45:48
一、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)
最新文章
- 页面嵌入dom与被嵌入iframe的攻防
- POMDP
- C/C++ 程序的build过程
- OAuth2.0 在 SSO中的应用~
- TAT,我的LCT转双旋了
- Convention插件 struts零配置
- web app 开发必不可少的滑动插件 Flipsnap
- Python对象初探
- Matplot中文乱码完美解决方式
- UIAlertView的使用方法
- HTTPS 服务器搭建
- div+css+javascript 走马灯图片轮换显示
- 《Linux内核设计与实现》内存管理札记
- 纯CSS滑动效果
- poj1265&;&;2954 [皮克定理 格点多边形]【学习笔记】
- Kafka-python 客户端导致的 cpu 使用过高,且无法消费消息的问题
- unity setactive的使用
- Sample Means(耶鲁大学教材)
- 快速构建springmvc+spring+swagger2环境
- DATEDIF函数
热门文章
- Paper | Toward Convolutional Blind Denoising of Real Photographs
- Serializable接口的意义和用法
- MAT 4378 – MAT 5317, Analysis of categorical
- Visual Studio 语法高亮插件推荐
- Django学习笔记(16)——扩展Django自带User模型,实现用户注册与登录
- 解决 IDEA 无法找到 java.util.Date 的问题
- 转 OpenCV Mat 数据读写
- dedecms用runphp功能,写for循环,@me输出不出来
- 升级GCC
- PIE SDK水体指数法