day38 元类

exec模块

是什么

exec是一个python内置模块

exec的作用

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

怎么用

参数一:字符串形式的Python代码

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

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

调用exec()

# 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)#{'x': 10
print(local_dict)#{'y': 20}

元类

什么是元类

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

元类的作用

​ 元类可以帮我们控制类的创建

​ 元类可以帮我们控制类的调用

怎么自定义创建元类

1)自定义一个元类,继承type,派生出自己的属性与方法。

2)给需要使用的类,通过metaclass指定自定义好的元类

​ —class Chinesse(metaclass='自定义的元类')

# 自定义元类
class MyMeta(type):
    # 子类的方法与父类的方法一样,先用子类的,子类覆盖父类的__init__方法
    #控制了类的定义
    '''
    class_name:类名
    class_base:父类
    class_dict:类的名称空间
    '''
    def __init__(self,class_name,class_base,class_dict):
        super().__init__(class_name,class_base,class_dict)
        print(class_name)
        print(class_base)
        print(class_dict)
        #判断字符串首字符是否大写
        if not class_name.istitle():
            raise TypeError('类的首字母必须大写')

        #控制类中必须要有注释
        if not class_dict.get('__doc__'):
            raise TypeError('类内部必须要写注释')

        # 模拟type元类内部做的事情
        #元类触发的__call__可以控制类的调用,调用__call__会触发一下两点

    def __call__(self,*args,**kwargs):
        #1.会调用__new__(),会创建一个空对象
        obj=object.__new__(self)
        #2.会执行__init__(self,*args,**kwargs)
        obj.__init__(*args,**kwargs)
        return obj
    #可以通过元类内部的__new__控制对象的创建
    def __new__(cls, *args, **kwargs):
        return type.__new__(cls, *args, **kwargs)

#metaclass-->自定义的元类
# 因为Foo类继承了元类,必须手动继承object

class Foo(object,metaclass=MyMeta):
    '''
        reetre'''
    x=10

    def __init__(self,y,z):
        self.y=y
        self.z=z

    def f1(self):
        print('from Foo f1')
   
foo=Foo(20,30)#调用Foo对象,会触发__call__

orm

orm:对象关系映射---》映射到数据库MySQL中的数据表

类名---》表名

对象---》一条记录

对象.属性---》字段

模拟Django的orm,为了将数据库的增删改查全部封装成一个个的方法,比如sava,delete,update,select

字段类

#1.创建字段的类型,对应数据表中的一个个字段的创建规范
class Field:
    def __init__(self,name,colum_type,primary_key,default):
        self.name=name
        self.colum_type=colum_type
        self.primary_key=primary_key
        self.default=default

#Integer
class IntegerField(Field):
    def __init__(self,name,colum_type='int',primary_key=False,default=0):
        super().__init__(name,colum_type,primary_key,default)

#String
class StringField(Field):
    def __init__(self, name, colum_type='varchar(64)', primary_key=False, default=None):
        super().__init__(name, colum_type, primary_key, default)

元类


'''
元类需要处理的问题:
    1.一张表必须要有一个表名。
    2.给数据表类,强制必须要有一个主键,主键必须是唯一的。
    3.将数据表中,所有的字段对象,都存放在一个独立的字典中
        存不是目的,目的是为了取值方便。
'''
class OrmMetaClass(type):
    def __new__(cls,class_name,class_base,class_dict):
        # print(class_name)
        #过滤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)

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

Models类

'''
问题1: 解决代码荣誉问题,比如有100张表,需要写100次__init__。
解决1: 继承一个父类,父类中定义一个__init__。

问题2: 无法预测每一张表中的字段是什么,无法通过父类的__init__解决问题。
解决2: 通过继承字典,内部的__init__, 可以接受“任意个数”的“关键字参数”。

问题3: 继承字典的类实例化的对象,无法通过“对象.属性”的方式存取值。
解决3: 通过__setattr__,__getattr__来实现,让字典对象与普通对象一模一样,并且具备字典原有的特性。

'''
class Models(dict,metaclass=OrmMetaClass):
    #会在 对象.属性 没有时触发
    def __getattr__(self, item):
        print(item,'调用没有的属性时触发')
        #将字典中的key对应的值返回给对象
        return self.get(item) #dict_obj.get(key)

    #在 对象.属性=值 时触发
    def __setattr__(self, key, value):
        print(key,value)
        # 给字典对象本身赋值
        self[key]=value

模型表类

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

#电影表类
class Movie(Models):
    # 强调:最好与字段类型的name属性同名
    user_id = IntegerField(name='user_id',primary_key=True)
    user_name = StringField(name='name')
    pwd = StringField(name='pwd')
posted @ 2019-11-04 22:17  风啊风啊  阅读(118)  评论(0编辑  收藏  举报