元类type以及利用元类实现模型类ORM

Python 中的内置元类为:type

type:是元类,所有的类都是通过type创建出来的。

object:顶层的基类,所有类的继承的顶层父类都是boject.

可通过class来定义类,也可以通过type来定义类。

type(name,bases,attr_dict)调用type():

        name:指定类名,将成为该类的name属性。

        bases:指定继承类的基类元祖,将成为该类的bases属性。

        attr_dict:指定包含类主体定义的名称空间字典,将成为该类的dict属性。

       

"""
type创建类三参数:
    1.列名:str
    2.继承的父类:tupe
    3.属性和方法:字典,以键值对的形式表示属性和方法
"""


# type中创建方法:
def func(self):
    print('---元类中加入方法----')


Test = type('Test999', (object,), {'name': "春田", 'age': 4, "function666": func})


class Info(object):
    attr = 100
    __attr1 = 200


if __name__ == '__main__':
    t = Test()
    i = Info()
    print(Test)     # <class '__main__.Test999'>
    print(Info)     # class '__main__.Info'>
    print(t)        # <__main__.Test999 object at 0x7fb5400b7e20>
    print(i)        # <__main__.Info object at 0x7fb5400b7eb0>
    # 查看父类
    print(Test.__base__)    # <class 'object'>
    # 查看当前文件路径
    print(__file__) # /Users/jeanettian/PycharmProjects/demo/dataType/元类Type.py
    # 判断类型
    print(isinstance(t,Test)) # True

通过继承内置元类type来实现自定义元类

class MyMetaClass(type):
    """通过继承python内置的元类type,来实现自定义元类"""

    def __new__(cls, name, bases, attr_dict, *args, **kwargs):
        """
        要实现自定义元类,也要重写python内置元类type的__new__方法,tupe创建类
        的时候有三个参数,通过type自定义时,也要传入type的三个参数:
            1。name: 类名(字符串)
            2。bases: 继承的父类(放入元祖)
            3。attr_dict: 属性和方法(放入字典)
        """
        print('----这是自定义元类-----')
        return super().__new__(cls, name, bases, attr_dict)


class Test(metaclass=MyMetaClass):
    """
    继承自定义的元类必须通过metaclass关键字指定,才能继承自定义元类
    """
    name = "春田"


class Test2(Test):
    attr = "Test2"


if __name__ == '__main__':
    pass
    # 查看Test类继承的类
    print(type(Test))
    # 查看Test2类继承的类
    print(type(Test2))
    # 输出:
    ----这是自定义元类 - ----
    ----这是自定义元类 - ----
    <class '__main__.MyMetaClass'>
    <class '__main__.MyMetaClass'>

通过元类来控制属性名全为大写

class MyMetaClass(type):
    """通过继承python内置的元类type,来实现自定义元类,自定义元类能使属性名大写"""

    def __new__(cls, name, bases, attr_dict, *args, **kwargs):
        """
        要实现自定义元类,也要重写python内置元类type的__new__方法,tupe创建类
        的时候有三个参数,通过type自定义时,也要传入type的三个参数:
            1。name: 类名(字符串)
            2。bases: 继承的父类(放入元祖)
            3。attr_dict: 属性和方法(放入字典)
        """
        print('----这是自定义元类-----')
        attr_dict_list = [itme for itme in attr_dict.items()]
        for k,v in attr_dict_list:
      # for k,v in attr_dict.items():  # 字典便利的时候不允许对字典数据增减
            attr_dict.pop(k)  # 删除键值对
            attr_dict[k.upper()] = v    # 替换为大写的键值对

        attr_dict["__slots__"] = ["name","age", "attr"]  # 控制创建出来的属性
        return super().__new__(cls, name, bases, attr_dict)


class Test(metaclass=MyMetaClass):
    name = "春田"
    age = 4


class Test2(Test):
    attr = "Test2"


if __name__ == '__main__':
    print(Test.__dict__)
    # 输出:
    # {'__MODULE__': '__main__', '__QUALNAME__': 'Test', 'NAME': '春田', 'AGE': 4, '__slots__': ['name', 'age', 'attr']

ORM模型实现思路:

        1.类对应表,创建类的时候需要自动生成对应的数据表。

        2.对象对应一条数据,创建一个对象,需要在数据表中添加一条数据。

        3.属性对应字段,修改对象属性的同时需要修改数据库中对应的字段。

实例:

from define_ORM import BaseField, CharField, IntegerField, BoolField

"""
利用元类来实现模型类
"""


# 定义元类
class FieldMetaClass(type):
    """模型类的元类
    通过此元类来控制Uer模型类对象的生成
    通过元类的控制,可以在数据库中生成模型类对应的表
    """

    def __new__(cls, name, bases, attr_dict, *args, **kwargs):
        print('----触发了元类')
        # 调用元类生产模型类时须传入元类必须的三个参数:name,bases,attr_dict
        table_name = name.lower()  # name:元类3参数中的类名name,此处为:User/user,转换为小写,对应数据表名
        # print(attr_dict)   # {'__module__': '__main__', '__qualname__': 'User', '__doc__': '用户模型类,一个模型类就是一个数据表名', 'username': <define_ORM.CharField object at 0x7f9fc02ea040>, 'pwd': <define_ORM.CharField object at 0x7f9fc02eaeb0>, 'age': <define_ORM.IntegerField object at 0x7f9fc02eaca0>, 'marry': <define_ORM.BoolField object at 0x7f9fc02eaa30>}

        # 过滤attr_dict中的不需要的属性,只留模型类中的属性字段
        fields = {}  # filds用来存放存放模型类中属性字段和数据表中字段的对应关系,属性字段都继承于BaseField
        for k, v in attr_dict.items():
            if isinstance(v, BaseField):  # 判断属性值是否是字段类型的,因为字段类型都继承于BaseField类
                fields[k] = v
        # print(fields)   # {'username': <define_ORM.CharField object at 0x7f9ee01ba040>, 'pwd': <define_ORM.CharField object at 0x7f9ee01baeb0>, 'age': <define_ORM.IntegerField object at 0x7f9ee01baca0>, 'marry': <define_ORM.BoolField object at 0x7f9ee01baa30>}

        # 将字典类型的fields和表名加入attr_dict中,传入new,User模型类也就拥有了t_name和fields属性,控制生成表信息
        attr_dict["t_name"] = table_name
        attr_dict["fields"] = fields

        return super().__new__(cls, name, bases, attr_dict)  # 调用type元类的new方法生成模型类


class User(metaclass=FieldMetaClass):
    """用户模型类,一个模型类就是一个数据表名"""
    username = CharField()
    pwd = CharField()
    age = IntegerField()
    marry = BoolField()


if __name__ == '__main__':
    print(User.fields)
    print(User.t_name)
    pass
    tian = User()
    tian.name = '春田'
    print(tian.name)
    # 输出:
    ----触发了元类
    {'username': < define_ORM.CharField object at 0x7fcce8183af0 >, 'pwd': < define_ORM.CharField object at
    0x7fcce8183a60 >, 'age': < define_ORM.IntegerField object at 0x7fcce8183910 >, 'marry': < define_ORM.BoolField object at 0x7fcce8183760 >}
    user
    春田

走到这一步有个问题,我们每次创建Usr对象,给对象绑定属性都要挨个通过User.name = xxx,User.pwd= xxxx,User.marry = xxx来绑定,未免太过繁琐,有没有办法实现chutnian=User(name = "春田“,age=4,marry=False)这种一次性方式添加数据呢?有,方式如下:

新定义个BaseModel类,定义其__init__方法,接收他的子类需要绑定的属性字段,并指定BaseModel类代替User类为元类创建,User等模型类继承BaseModel即可,这样,User等模型类通过传入的关键字参数,就可调用父类BaseModel的init方法,完成需求

1.defin_ORM.py模块

"""
通过描述器实现ORM模型
"""


class BaseField(object):
    pass


class CharField(BaseField):
    def __init__(self, max_length=20):
        self.max_length = max_length

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        # 首先判断是否为空
        if value is not None:
            # 再判断是否是字符串
            if isinstance(value, str):
                # 再判断长度是否符合要求
                if len(value) <= self.max_length:
                    self.value = value
                else:
                    raise TypeError('length need less than {}'.format(self.max_length))
            else:
                raise TypeError('need a str')
        else:
            raise TypeError("can not be None")

    def __delete__(self, instance):
        self.value = None


class IntegerField(BaseField):

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        # 首先判断是否为空
        if value is not None:
            # 再判断是否是整数int
            if isinstance(value, int):
                self.value = value
            else:
                raise TypeError('need a int')
        else:
            raise TypeError("can not be None")

    def __delete__(self, instance):
        self.value = None


class BoolField(BaseField):
    def __init__(self):
        pass

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        if isinstance(value, bool):
            self.value = value
        else:
            raise Exception('need a boolean type')


class UserModel(object):
    # 定义用户信息的模型类
    name = CharField(max_length=20)  # 定义:name只能赋值为字符串
    pwd = CharField(max_length=40)
    age = IntegerField()  # 定义:age只能赋值为整数
    marry = BoolField()  # 定义:marry只能是布尔类型


if __name__ == '__main__':
    user = UserModel()
    user.name = "春田"
    print(user.name)  # 输出: 春田
    user.age = 130
    print(user.age)  # 输出: 130
    user.marry = False
    print(user.marry)
    user.pwd = 'wsdgdgdrgerdsfs方式范德萨发阿瑟费萨法 sfa fda fsdf sdf  fg'
    print(user.pwd)  # 输出: TypeError: length need less than 40
from define_ORM import BaseField, CharField, IntegerField, BoolField

"""
利用元类来实现模型类
"""


# 定义元类
class FieldMetaClass(type):
    """模型类的元类
    通过此元类来控制Uer模型类对象的生成
    通过元类的控制,可以在数据库中生成模型类对应的表
    """

    def __new__(cls, name, bases, attr_dict, *args, **kwargs):
        # print('----触发了元类')
        if name == 'BaseModel':  # 因为下面定义BaseModel类时也会调用FieldMetaClass的new方法,
                                # 所以需要判断类名是否是BaseModel,如果是就直接创建,不需要过滤字段属性
            return super().__new__(cls,name,bases,attr_dict)

        # 调用元类生产模型类时须传入元类必须的三个参数:name,bases,attr_dict
        else:   # 模型类才调用此部分过滤属性绑定的逻辑
            table_name = name.lower()  # name:元类3参数中的类名name,此处为:User/user,转换为小写,对应数据表名
            # print(attr_dict)   # {'__module__': '__main__', '__qualname__': 'User', '__doc__': '用户模型类,一个模型类就是一个数据表名', 'username': <define_ORM.CharField object at 0x7f9fc02ea040>, 'pwd': <define_ORM.CharField object at 0x7f9fc02eaeb0>, 'age': <define_ORM.IntegerField object at 0x7f9fc02eaca0>, 'marry': <define_ORM.BoolField object at 0x7f9fc02eaa30>}

            # 过滤attr_dict中的不需要的属性,只留模型类中的属性字段
            fields = {}  # filds用来存放存放模型类中属性字段和数据表中字段的对应关系,属性字段都继承于BaseField
            for k, v in attr_dict.items():
                if isinstance(v, BaseField):  # 判断属性值是否是字段类型的,因为字段类型都继承于BaseField类
                    fields[k] = v
            # print(fields)   # {'username': <define_ORM.CharField object at 0x7f9ee01ba040>, 'pwd': <define_ORM.CharField object at 0x7f9ee01baeb0>, 'age': <define_ORM.IntegerField object at 0x7f9ee01baca0>, 'marry': <define_ORM.BoolField object at 0x7f9ee01baa30>}

            # 将字典类型的fields和表名加入attr_dict中,传入new,User模型类也就拥有了t_name和fields属性,控制生成表信息
            attr_dict["t_name"] = table_name
            attr_dict["fields"] = fields

            return super().__new__(cls, name, bases, attr_dict)  # 调用type元类的new方法生成模型类


class BaseModel(metaclass=FieldMetaClass):
    """模型类的父类,代替模型类由元类FieldMetaClass创建"""

    def __init__(self, **kwargs):
        # 解包,并绑定属性
        for k, v in kwargs.items():
            # self.k =v  # 会报错,因此处k为字符串,self.k相当于成了sefl."name"。
            # 设置属性,遍历所有对象属性,进行对象的属性设置
            setattr(self, k, v)  # 第一个参数:self为对象,第二个参数:k为属性名,第三个参数:v为属性值


class User(BaseModel):
    """用户模型类,一个模型类就是一个数据表名"""
    username = CharField()
    pwd = CharField()
    age = IntegerField()
    marry = BoolField()


if __name__ == '__main__':
    t =User(username ='春田',age =4, marry =False,pwd = '123')
    print(t.username)
    # 输出:
    # 春田

生成数据t后,如何保存到数据表中呢?通过save()方法保存

from define_ORM import BaseField, CharField, IntegerField, BoolField

"""
利用元类来实现模型类
"""


# 定义元类
class FieldMetaClass(type):
    """模型类的元类
    通过此元类来控制Uer模型类对象的生成
    通过元类的控制,可以在数据库中生成模型类对应的表
    """

    def __new__(cls, name, bases, attr_dict, *args, **kwargs):
        # print('----触发了元类')
        if name == 'BaseModel':  # 因为下面定义BaseModel类时也会调用FieldMetaClass的new方法,
            # 所以需要判断类名是否是BaseModel,如果是就直接创建,不需要过滤字段属性
            return super().__new__(cls, name, bases, attr_dict)

        # 调用元类生产模型类时须传入元类必须的三个参数:name,bases,attr_dict
        else:  # 模型类才调用此部分过滤属性绑定的逻辑
            table_name = name.lower()  # name:元类3参数中的类名name,此处为:User/user,转换为小写,对应数据表名
            # print(attr_dict)   # {'__module__': '__main__', '__qualname__': 'User', '__doc__': '用户模型类,一个模型类就是一个数据表名', 'username': <define_ORM.CharField object at 0x7f9fc02ea040>, 'pwd': <define_ORM.CharField object at 0x7f9fc02eaeb0>, 'age': <define_ORM.IntegerField object at 0x7f9fc02eaca0>, 'marry': <define_ORM.BoolField object at 0x7f9fc02eaa30>}

            # 过滤attr_dict中的不需要的属性,只留模型类中的属性字段
            fields = {}  # filds用来存放存放模型类中属性字段和数据表中字段的对应关系,属性字段都继承于BaseField
            for k, v in attr_dict.items():
                if isinstance(v, BaseField):  # 判断属性值是否是字段类型的,因为字段类型都继承于BaseField类
                    fields[k] = v
            # print(fields)   # {'username': <define_ORM.CharField object at 0x7f9ee01ba040>, 'pwd': <define_ORM.CharField object at 0x7f9ee01baeb0>, 'age': <define_ORM.IntegerField object at 0x7f9ee01baca0>, 'marry': <define_ORM.BoolField object at 0x7f9ee01baa30>}

            # 将字典类型的fields和表名加入attr_dict中,传入new,User模型类也就拥有了t_name和fields属性,控制生成表信息
            attr_dict["t_name"] = table_name
            attr_dict["fields"] = fields
            
            # 生成sql表的语句,并执行
            print("此处应生成数据表的操作")

            return super().__new__(cls, name, bases, attr_dict)  # 调用type元类的new方法生成模型类


class BaseModel(metaclass=FieldMetaClass):
    """模型类的父类,代替模型类由元类FieldMetaClass创建
    模型类中就不用再定义init方法了,只需要定义属性字段
    """

    def __init__(self, **kwargs):
        # 解包,并绑定属性
        for k, v in kwargs.items():
            # self.k =v  # 会报错,因此处k为字符串,self.k相当于成了sefl."name"。
            # 设置属性,遍历所有对象属性,进行对象的属性设置
            setattr(self, k, v)  # 第一个参数:self为对象,第二个参数:k为属性名,第三个参数:v为属性值

    def save(self):
        """# 保存一条数据就应该生成一条对应的sql语句"""
        # 获取表名
        t_name = self.t_name
        # 获取字段名称
        fields = self.fields  # self.fields是元类FieldMetaClass的fields
        print('fields',
              fields)  # fields {'username': <define_ORM.CharField object at 0x7f9478214f70>, 'pwd': <define_ORM.CharField object at 0x7f9478214e80>, 'age': <define_ORM.IntegerField object at 0x7f9478214d00>, 'marry': <define_ORM.BoolField object at 0x7f9478214100>}

        # 创建一个字典用来存储键值对
        field_dict = {}
        # 获取对应字段的值
        print('fields.keys():', fields.keys())  # dict_keys(['username', 'pwd', 'age', 'marry'])
        for field in fields.keys():
            print('field', field)  # username username age marry
            field_dict[field] = getattr(self, field)  # getattr() 函数用于返回一个对象属性值。
        print("field_dict:", field_dict)  # field_dict: {'username': '春田', 'pwd': '123', 'age': 4, 'marry': False}
        # 生成对应的sql语句
        print('---field_dict.values():',
              field_dict.values())  # ---field_dict.values(): dict_values(['春田', '123', 4, False])
        sql = 'insert into {} value{}'.format(t_name, field_dict.values())
        print(sql)  # insert into user valuedict_values(['春田', '123', 4, False])


class User(BaseModel):
    """用户模型类,一个模型类就是一个数据表名"""
    username = CharField()
    pwd = CharField()
    age = IntegerField()
    marry = BoolField()


if __name__ == '__main__':
    t = User(username='春田', age=4, marry=False, pwd='123')
    t.save()
    print(t.username)
    # 输出:
# 此处应生成数据表的操作
# fields {'username': <define_ORM.CharField object at 0x7fa6a012cf70>, 'pwd': <define_ORM.CharField object at 0x7fa6a012ce80>, 'age': <define_ORM.IntegerField object at 0x7fa6a012cd00>, 'marry': <define_ORM.BoolField object at 0x7fa6a012c100>}
# fields.keys(): dict_keys(['username', 'pwd', 'age', 'marry'])
# field username
# field pwd
# field age
# field marry
# field_dict: {'username': '春田', 'pwd': '123', 'age': 4, 'marry': False}
# ---field_dict.values(): dict_values(['春田', '123', 4, False])
# insert into user valuedict_values(['春田', '123', 4, False])
# 春田

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chuntian_tester

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值