一、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. php 学习笔记之搭建开发环境(mac版)

    Mac 系统默认集成了很多开发工具,其中就包括 php 所需要的一些软件工具. 下面我们将搭建最简单的 php 开发环境,每一步都会验证上一步的操作结构,请一步一步跟我一起搭建吧! web 服务器之 ...

  2. Alpha冲刺(1/4)

    队名:天码行空 组长博客连接 作业博客连接 团队燃尽图(共享): GitHub当日代码/文档签入记录展示(共享): 组员情况: 组员1:卢欢(组长) 过去两天完成了哪些任务:SVN管理工具搭建 展示G ...

  3. 【2019.8.9 慈溪模拟赛 T1】数论(a)(打表找规律)

    莫比乌斯反演 血亏! 比赛时看到这题先写了个莫比乌斯反演,然后手造了几组数据和暴力对拍的时候发现,居然答案就是\(nm\)... 吐槽数据范围太小... 下面给上出题人对此题的解释: 原式的物理意义, ...

  4. Paper | Multi-scale Dense Networks for Resource Efficient Image Classification

    目录 故事背景 方法 两种加速策略 网络设计 网络优化 失败设计 回头品味 实验 数据集和数据处理 结果 第二次阅读 本文不是第一个提出early exit思想的 写作流畅 网络回顾 其他 发表在IC ...

  5. 理解CMS GC日志

    本文翻译自:https://blogs.oracle.com/poonam/entry/understanding_cms_gc_logs 准备工作 JVM的GC日志的主要参数包括如下几个:-XX:+ ...

  6. svn merge操作

    使用SVN做Merge操作时,会包含6个选项,下面就这6个选项给出详细的说明: 1.Merge a range of revisions 此类型应用最为广泛,主要是把源分支中的修改合并到目标分支上来. ...

  7. LeetCode20——有效的括号

    在记事本中写算法题和在纸上写其实感觉差不多,反正是不能进行调试.想起某高手的话,写代码要做到“人机合一”,写高级语言时(指的是 C 和 C++)脑海中要知道当前写的代码对应的反汇编代码,也就是要深入了 ...

  8. LINQ 之 LookUp

    声明:本文为www.cnc6.cn原创,转载时请注明出处,谢谢! 本文作者文采欠佳,文字表达等方面不是很好,但实际的代码例子是非常实用的,请作参考. 一.先准备要使用的类: 1.Person类: cl ...

  9. CentOS系统安装Python3

    准备: CentOS 6.4系统 Python-3.6.5.tgz 下载地址: 官网:https://www.python.org/downloads/release/python-365/ 镜像:h ...

  10. 【mybatis】mybatis传参的几种方式

    参考地址: https://my.oschina.net/liuzelin/blog/2966633