一、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. luoguP2463 [SDOI2008]Sandy的卡片

    题意 显然加上一个数相等就是差分数组相等,于是问题变为求几个串的最长公共子串. 这里我学习了如何用SA求LCS. 首先问题要转化成求一些后缀的最长公共前缀,要求这些后缀分属不同的串. 于是二分答案,于 ...

  2. React、Vue、Angular对比 ---- 介绍及优缺点

    React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站, 并于 2013年 5 月开源.React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它.它 ...

  3. 关于XSS攻击

    1.XSS XSS(Cross Site Scripting)攻击全称跨站脚本攻击,为了不与CSS(Cascading Style Sheets)混淆,故将跨站脚本攻击缩写为XSS,XSS是一种经常出 ...

  4. h5 ios移动端,键盘收起以后页面不归位

    $('input,textarea').on('blur',function(){ window.scroll(0,0); }); $('select').on('change',function() ...

  5. 数据仓库005 - 复习Linux shell命令 - crontab调度 sh脚本 后台执行 软连接

    一.crontab调度 对于linux 自带crontab而言,      xxx.sh的一般编写格式以#!/bin/bash 解释器开头,可在脚本中加入: date 但是,shell脚本执行 需要 ...

  6. oracle中如何更改一个表的一个字段属性(名称,类型)

    修改字段的属性,名称方法 --修改某一个字段的类型,当该字段不为null时alter table 表名add 字段NUMBER(11,0) default 0 not null;--添加表一个字段 A ...

  7. elementui树表修改子节点不能实时更新的解决办法

    在使用ElementUI提供的树表(el-table)的时候发现,如果手动通过JS修改了某个节点的children中的一条记录(子节点)的话,并不会自动刷新. 简单分析了一下,原因大概是因为VUE的数 ...

  8. 车位iou计算

    车位检测中,判断多帧图像检测出的车位是否是同一个车位.计算其IOU. 判断一个点是否在一个四边形内 Approach : Let the coordinates of four corners be ...

  9. 使用角色管理工具 安装或配置microsoft.net framework 3.5 sp1

    解决方法:

  10. Python - 时间相关与计划任务

    Python - 时间处理与定时任务 1.计算明天和昨天的日期 # 获取今天.昨天和明天的日期 # 引入datetime模块 import datetime #计算今天的时间 today = date ...