day46

exec模块的补充

是什么?

exec是一个Python内置模块。

exec的作用:

'''
x = 10
def func1():
pass
'''
可以把"字符串形式"的python代码,添加到全局空间或局部名称空间中。

怎么用:

参数1: 字符串形式的python代码

参数2: 全局名称空间字典

参数3: 局部名称空间字典

调用exec()

元类

什么是元类?

元类就是类的类,Chinese类的类是type,type是所有类的类,type就是一个元类。

元类的作用?

元类可以帮我们控制类的创建。
元类可以帮我们控制类的调用。

怎么自定义创建元类:

  1. 自定义一个元类,继承type,派生出自己的属性与方法。
  2. 给需要使用的类,通过metaclass指定自定义好的元类。
    class Chinese(metaclass='自定义的元类'):

自定义元类

# 自定义元类
class MyMeta(type):
    # 子类的方法与父类的方法一样,先用子类的,子类覆盖父类的--init__方法。
    # 控制了类的定义
    def __init__(self,class_name,class_base,class_dict):
        # print(class_name)
        
        # 判断字符串首字母是否大写
        if not class_name.istitle():
            raise TypeError('类的首字母必须大写!')
            
        # 判断类中必须要有注释
        if not class_dict.get('__doc__'):
            raise TypeError('类内部必须要写注释!')
            
        # print(class_base)
        # print(class_dict)
        super().__init__(class_name,class_base,class_dict)
        
    # 模拟type元类内部做的事情
    # 元类触发的__call__可以控制类的调用。调用__call__会触发一下两点
    def __call__(self,*args,**kwargs):
        # 1.会调用__new__() -->obj,会创建一个空对象
        obj = object.__new__(self)
        # 2.会执行__init__(obj,*args,**kwargs),
        obj.__init__(*args,**kwargs)
        return obj
    
    # 可以通过元类内部的__new__控制对象的创建
    def __new__(cls,*args,**kwargs):
		pass
        

2.优酷架构

  • ATM

    ​ 用户视图层

    ​ 接口层

    ​ 数据层

    ​ dict

    ​ json
    ​ 优点:
    ​ 数据可以跨平台。

    ​ 缺点:
    ​ 不能存对象,也不能直接获取对象。 {。。。}
    ​ 不能通过“对象.属性”的方式 存、取值。
    ​ 存储速度比pickle慢。

  • 选课系统

    ​ 用户视图层

    ​ 接口层

    ​ 数据层

    ​ models:

    ​ obj

    ​ pickle
    ​ 优点:
    ​ 可以通过“对象.属性”的方式 存、取值。
    ​ 能存对象,也能直接获取对象。

    ​ 缺点:
    ​ 不能跨平台。

  • 优酷

    ​ 用户视图层
    接口层
    数据层
    存储对象 ---> dict ---> Json ---> MySQL
    MySQL ---> Json ---> dict ---> 获取对象

ORM: 对象关系映射

映射到数据库MySQL中的数据表

类名 ---》表名

对象 ---》一条记录

对象.属性 ---》字段

模拟Django的ORM,为了,将数据库的 增、删、改、查,全部封装

成一个个的方式,比如:save,delete,update,select。

# 创建字段的类型,对应数据表中的一个个字段的创建规范
class Field:
    def __init__(self,name,column_type,primary_key,default):
        self.name = name
        self.column_type = column_type
        self.primary_key = primary_key
        self.default = default
        
# Integer
class IntegerField(Field):
    def __init__(self,name,column_type='int',primary_key=False,default=0):
        super().__inti__(name,column_type,primary_key,default)
       
# String
class StringField(Field):
    def __init__(self,name,column_type='varchar(64)',primary_key=False,default=None):
        super().__inti__(name,column_type,primary_key,default)
        

元类需要处理的问题:

  1. 一张表必须要有一个表名。

  2. 给数据表,强制必须要有一个主键,主键必须是位移的。

  3. 将数据表中,所有的字段对象,都存放在一个独立的字典中

    存不是目的,目的是为了取值方便。

class OrmMetaClass(type):
    # def __new__(cls,*args,**kwargs):
    # print(args,'args........')
    # print(kwargs,'kwargs....')
    
    # OrmMetaClass(class,class_name,class_base,class_dict)
    
    def __new__(cls, class_name, class_base, class_dict):
        # print(class_name, '类名--》表名')
        # print(class_base, '基类/父类')
        # print(class_dict, '类的名称空间')

        # 过滤Models类
        if class_name == 'Models':
            # models类中,什么都不做,将类原路返回。
            return type.__new__(cls, class_name, class_base, class_dict)

        # 1.一张表必须要有表名
        # 假如table_name没有值,则将类名当做表名
        table_name = class_dict.get('table_name', class_name)  # get--> self.table_name

        # 2.主键名
        primary_key = None

        # 3.定义一个空字典, 专门用来存放字段对象
        mappings = {}

        # 遍历名称空间中所有的属性
        for key, value in class_dict.items():
            # print(key, value)
            # 除了有字段,还有其他字段以外的属性
            # 过滤字段对象以外的内容
            if isinstance(value, Field):
                mappings[key] = value

                # 判断字段对象primary_key是否为True
                if value.primary_key:
                    # 先判断初识的primary_key是否有值
                    # 判断主键是否已存在
                    if primary_key:
                        raise TypeError('只能有一个主键!')

                    # 若主键不存在,则给primary_key赋值
                    primary_key = value.name

        # 节省资源: 因为mappings与原类中名称空间中的属性重复,为了节省内存,剔除重复的属性。
        for key in mappings.keys():
            class_dict.pop(key)

        # 判断是否有主键
        if not primary_key:
            raise TypeError('必须有一个主键')

        # 给类的名称空间添加表名
        class_dict['table_name'] = table_name
        # 给类的名称空间添加主键名
        class_dict['primary_key'] = primary_key
        # 给类的名称空间添加一个mappings字典,字典中拥有所有字段属性
        class_dict['mappings'] = mappings
        return type.__new__(cls, class_name, class_base, class_dict)


class Models(dict, metaclass=OrmMetaClass):  # OrmMetaClass(Models, Models_name, base, class_dict)
    def __getattr__(self, item):
        print(item, '调用没有的属性时会触发...')
        # 将字典的值,返回
        return self.get(item)

    def __setattr__(self, key, value):
        print(key, value)
        self[key] = value


# 用户表类
class User(Models):  # ---> 表名
    # table_name = 'user_info'
    # 强调: 最好与字段类型的name属性同名
    user_id = IntegerField(name='user_id', primary_key=True)
    user_name = StringField(name='name')
    pwd = StringField(name='pwd')
    pass


# 用户表类
class Movie(Models):  # ---> 表名
    # table_name = 'user_info'
    # 强调: 最好与字段类型的name属性同名
    user_id = IntegerField(name='user_id', primary_key=True)
    user_name = StringField(name='name')
    pwd = StringField(name='pwd')
    pass


if __name__ == '__main__':
    print(User.__dict__)
posted @ 2019-11-04 20:36  Isayama  阅读(104)  评论(0编辑  收藏  举报