一、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)

二、元类

(一)什么是元类

  1. python中一切皆对象,而类本质上也是另一个类实例化出来的对象,而这个类就叫做元类(简称类的类),内置的元类为type
  2. 元类可以控制类的创建

(二)通过class关键字创建类

class创建类时,内部会自动调用元类type,type会帮我们创建一个自定义类,此时会传入三个参数:

  1. 类名class_name
  2. class_bases = (object,)
  3. 类的名称空间class_dic,由执行类体代码得到的

(三)自定义元类控制类的创建

  • 自定义创建元类:

    1. 自定义一个元类,继承type,派生出自己的属性和方法
    2. 通过metaclass指定自定义好的元类,来控制类的创建
  • 通过元类type创建类,会在调用的时候(__call__)做三件事:
    1. 产生一个空对象
    2. 调用__init__方法初始化对象obj
    3. 返回初始化好的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

  1. ORM:对象关系映射,将类和数据库中的数据表进行映射

    类名对应表名,对象对应记录,属性对应字段

  2. 这样可以通过对象.属性的方法直接访问到表数据,将数据库的增删改查全部封装成一个个函数

# 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)

(day38)元类+ORM的更多相关文章

  1. 元类实现ORM

    1. ORM是什么 ORM 是 python编程语言后端web框架 Django的核心思想,"Object Relational Mapping",即对象-关系映射,简称ORM. ...

  2. 使用元类 编写ORM

    元类 一句话: 元类定制类的创建行为 知识点 1.类的创建: python这种动态语言,函数和类的定义,不是编译时定义的,而是运行时动态创建的. Python解释器遇到class定义时,仅仅是扫描一下 ...

  3. python——type()、metaclass元类和精简ORM框架

    1.type()函数 if __name__ == '__main__': h = hello() h.hello() print(type(hello)) print(type(h)) Hello, ...

  4. 谈谈Python中元类Metaclass(二):ORM实践

    什么是ORM? ORM的英文全称是“Object Relational Mapping”,即对象-关系映射,从字面上直接理解,就是把“关系”给“对象”化. 对应到数据库,我们知道关系数据库(例如Mys ...

  5. python ORM理解、元类

    元类 参考链接:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143191 ...

  6. 04 -- 元类和ORM

    本篇主要介绍元类,为什么说一切皆对象:如何动态的创建类等:以及ORM,即什么是ORM等知识 一.元类 1.1 在Python中一切皆对象 在学习元类中我们首先需要了解一个概念-- python中一切皆 ...

  7. Python元类实战,通过元类实现数据库ORM框架

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第19篇文章,我们一起来用元类实现一个简易的ORM数据库框架. 本文主要是受到了廖雪峰老师Python3入门教程的启 ...

  8. python-元类和使用元类实现简单的ORM

    元类 面向对象中,对象是类的实例,即对象是通过类创建出来的,在python中,一切皆对象,同样,类也是一个对象,叫做类对象,只是这个类对象拥有创建其子对象(实例对象)的能力.既然类是对象,那么类是通过 ...

  9. 元类、orm

    目录 一.内置函数exec 二.元类 1. 什么是元类 2. 元类的作用 3. 创建类的两种方法 4. 怎么自定义创建元类 三.ORM 1. ORM中可能会遇到的问题 2. ORM中元类需要解决的问题 ...

随机推荐

  1. ResultMap(还没细看)

    前言 MyBatis是基于“数据库结构不可控”的思想建立的,也就是我们希望数据库遵循第三范式或BCNF,但实际事与愿违,那么结果集映射就是MyBatis为我们提供这种理想与现实间转换的手段了,而res ...

  2. 【CodeForces】CodeForcesRound576 Div1 解题报告

    点此进入比赛 \(A\):MP3(点此看题面) 大致题意: 让你选择一个值域区间\([L,R]\),使得序列中满足\(L\le a_i\le R\)的数的种类数不超过\(2^{\lfloor\frac ...

  3. SQLi_Labs通关文档

    SQLi_Labs通关文档 先列举一下sql基础语句 show databases; //查看数据库 use xxx; //使用某个数据库 show tables; //查看该数据库的数据表 desc ...

  4. Unreal Engine 4 系列教程 Part 7:音频教程

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  5. Wireshark使用入门

    目录 1. Wireshark介绍 1.1 客户端界面 1.2 Display Filter 的常用方法 1.3 界面上一些小TIPS 2. 使用Wireshark分析TCP三次握手过程 2.1 三次 ...

  6. Docker安装使用以及mlsql的docker安装使用说明

    1.检查内核版本,必须是3.10及以上 uname -r 2.安装 yum -y install docker #1.启动   docker systemctl start docker #1.1.验 ...

  7. mysql启动报错:Failed to start LSB: start and stop MySQL

    报错信息: [root@youxx- bin]# service mysql status Redirecting to /bin/systemctl status mysql.service ¡ñ ...

  8. Mysql权限整理及授权命令

    1.创建用户sql> use mysql;sql> create user 'Ruthless'@'%' identified by '123456';注意:Ruthless -> ...

  9. Mysql设置binlog过期时间并自动删除

    问题: Mysql数据库由于业务原因,数据量增长迅速,binlog日志会增加较多,占用大部分磁盘空间. 解决方案: 出于节约空间考虑,可进行删除多余binary日志,并设置定期删除操作. .查看bin ...

  10. C# NPOI Export DataTable C# NPOI导出DataTable 单元格自适应大小

    1.Install-Package NPOI -v 2.4.0 2. using NPOI.XSSF; using NPOI.XSSF.UserModel; using NPOI.SS.UserMod ...