一、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. C实现string字符串

    在C中实现string字符串,使用typedef将string定义为char *. #include <stdio.h> #include <stdlib.h> #includ ...

  2. Nginx 安装与部署配置

    下载 官方网站:https://nginx.org/en/download.html Windows下安装 安装 下载后解压(切记不能含有中文路径!!),文件结构如图(我解压的路径就有中文,记得拷贝放 ...

  3. node爬虫之图片下载

    背景:针对一些想换头像的玩家,而又不知道用什么头像的,作为一名代码爱好者,能用程序解决的,就不用程序来换头像,说干就干,然后就整理了一下. 效果图 环境配置 安装node环境 node -v node ...

  4. 重构与模式 (Joshua Kerievsky 著)

    第1章 本书的写作缘由 第2章 重构 第3章 模式 第4章 代码坏味 第5章 模式导向的重构目录 第6章 创建 第7章 简化 第8章 泛化 第9章 保护 第10章 聚集操作 第11章 实用重构 参考文 ...

  5. Python之爬虫-校花网

    Python之爬虫-校花网 #!/usr/bin/env python # -*- coding:utf-8 -*- import re import requests # 拿到校花网主页的内容 re ...

  6. 公式推导【ASRCF//CVPR2019】

    Dai K, Wang D, Lu H, et al. Visual Tracking via Adaptive Spatially-Regularized Correlation Filters[C ...

  7. 优雅的解决springboot Aop @Cacheable this不生效

    问题描述:在同一个类中springAop不生效,例如在同一个类中没有 @Cacheable的方法调用本类有 @Cacheable的方法,则缓存不会设置. 原因:springaop基于java prox ...

  8. redis 阻塞原因

    1.内因: A.api或数据结构使用不合理: 如:对一个包含上万元素的hash结构执行hgetall操作,数据量大且命令复杂度O(n),必然阻塞 B.慢查询:前面有介绍 C.大对象: 执行./redi ...

  9. Python 小案例实战 —— 简易银行存取款查询系统

    Python 小案例实战 -- 简易银行存取款查询系统 涉及知识点 包的调用 字典.列表的混合运用 列表元素索引.追加 基本的循环与分支结构 源码 import sys import time ban ...

  10. Xamarin移动开发备忘

    vs2017下: 1.debug用于本地生成和调试,release用于发布.区别主要在于: 安卓项目的生成选项属性中,开发者模式release是不勾的,而且高级里的cpu不同(debug是x86,re ...