python进阶--元类和ORM实现

元类和ORM

新式类和旧式类

定义

  • 新式类:继承了object的类才是新式类,Python 3.x中默认继承object,因此都是新式类。
  • 旧式类:继承了instance的类是旧式类(经典类),Python 2.x只有显式继承了object才是新式类。

区别:

  1. 新式类保持class与type的统一,通过__class__与type()访问的结果是一致的。也就是说新式类统一了类(class)和类型(type)的概念,而旧式类的类型(type)继承自instance类型,因此旧式类的类(class)和类型(type)是不一样的。
  2. 新式类是采用广度优先搜索,旧式类采用深度优先搜索。即:旧式类先深入继承树左侧,再返回,开始找右侧;新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动
  3. 新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中
  4. 新式类增加了__getattribute__方法

类和类型

python中一切皆对象,类也是对象。那么类也有类型。由于python3统一了类和类型,那么类就是类型,类型就是类

class A:
    pass

print(type(A))
print(A.__class__)

>
<class 'type'>
<class 'type'>

元类

类:类就是⼀组⽤来描述如何⽣成⼀个对象的代码段
元类(metaclass) :就是创建类的类,使用元类创建出对象,这个对象称为“类”。即:元类-----实例化----->对象-----实例化----->类实例对象,因此我们对类进行实例化实际上就是对元类的实例

元类和基类

type:元类,所有的类都是通过type创建
object:基类,所有类的继承顶层父类都是object

type

type: python内置缺省的的元类

type(object)   # 判断类型
type(name, bases, dict)   # 创建元类
	name -- 类的名称,str类型
	bases -- 基类的元组,tuple类型
	dict -- 类内定义的命名空间变量,dict类型

参考文档:https://iswbm.com/16.html

使用type创建元类

# 使用type创建元类
def func1(self):
    print('Hello World!')
    return func1.__name__


DemoClass = type('DemoClass', (object, ), {
    
    'name': '张三', 'function': func1})


a = DemoClass()

print(a.name)
print(a.function())

>
张三
Hello World!
func1
# 自定义元类必须继承自type
class DemoClass(type):
    def __new__(cls, name, bases, dict, *args, **kwargs):
        return super().__new__(cls, name, bases, dict)

class Demo(metaclass=DemoClass):
    name = '张三'
    pass

print(type(DemoClass))
print(type(Demo))
print(Demo.name)

>
<class 'type'>
<class 'type'>
张三

元类实现单例模式

# 对普通类进行实例化时,实际是对一个元类的实例(也就是普通类)进行直接调用实例化。
class DemoClass(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = type.__call__(cls, *args, **kwargs)
        return cls._instance

class Demo(metaclass=DemoClass):
    def __init__(cls, *args, **kwargs):
        pass

a = Demo()

b = Demo()

print(id(a))
print(id(b))

元类用途和ORM实现逻辑

元类的作用:可以使用元类,对类进行定制修改。
元类的用途:1、 创建API;2、 Django ORM
# 自定义元类
class DemoClass(type):
    """自定义元类,将类的所有属性变成大写"""
    def __new__(cls, name, bases, attr_dict, *args, **kwargs):
        for k,v in list(attr_dict.items()):  # 字典遍历时操作会出问题
            attr_dict.pop(k)
            attr_dict[k.upper()] = v

        attr_dict['__slots__'] = ['name', 'age']
        return super().__new__(cls, name, bases, attr_dict)

class Demo(metaclass=DemoClass):
    name = '张三'
    pass


a = Demo()
print(type(DemoClass))
print(type(Demo))
print(type(a))
print(Demo.__dict__)
print(a.__dict__)

>
<class 'type'>                  # 自定义的元类
<class '__main__.DemoClass'>    # 元类DemoClass的实例
<class '__main__.Demo'>         # 元类Demo的实例
{
    
    '__MODULE__': '__main__', '__QUALNAME__': 'Demo', 'NAME': '张三', '__slots__': ['name', 'age'], '__module__': '__main__', 'age': <member 'age' of 'Demo' objects>, 'name': <member 'name' of 'Demo' objects>, '__doc__': None}
AttributeError: 'Demo' object has no attribute '__dict__'

ORM实现

# field.py
class BaseField:
    pass

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

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

    def __set__(self, instance, value):
        if isinstance(value, int):
            self.value = value
        else:
            raise TypeError('need an int')

class CharFiled(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 isinstance(value, str):
            if len(value) <= self.max_length:
                self.value = value
            else:
                raise ValueError('字符串长度不超过{}字符'.format(self.max_length))
        else:
            raise TypeError('请输入字符串类型')

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

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

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

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

from field import CharFiled, IntField, BoolField, BaseField


class FieldMetaClass(type):
    """模型类的元类"""
    def __new__(cls, name, bases, dic, *args, **kwargs):
        if name == 'BaseModel':
            return super().__new__(cls, name, bases, dic)
        else:
            table_name = name.lower()   # 类名转换为小写的表名
            fields = {
    
    }
            for k, v in dic.items():
                if isinstance(v, BaseField):   # 判断属性是都是自己定义的字段类型
                    fields[k] = v
            dic['t_name'] = table_name
            dic['fields'] = fields
            create_table_sql = 'create table if not exists {} {} default charset=utf8;'.format(dic['t_name'],tuple(dic['fields'].keys()))
            print(create_table_sql)
            return super().__new__(cls, name, bases, dic)


class BaseModel(metaclass=FieldMetaClass):  # 为了保证模型类的纯粹,定义了次父类
    def __init__(self, **kwargs):
        for k, v in kwargs.items(): # 遍历模型类字段并设置属性
            setattr(self,k,v)

    def save(self):
        # 保存一条数据,生成对应的sql
        # 获取表名
        t_name = self.t_name
        # 获取字段名称
        fields = self.fields
        field_dict = {
    
    }
        for field in fields.keys():
            field_dict[field] = getattr(self, field) 

        sql = 'insert into {} value {};'.format(t_name,tuple(field_dict.values()))
        # 生成对应的sql
        print(sql)


class User(BaseModel):
    """用户模型类"""
    username = CharFiled()
    pwd = CharFiled()
    age = IntField()
    live = BoolField()


class Order(BaseModel):
    """订单模型类"""
    order = CharFiled()
    address = CharFiled()
    money = IntField()

r = User(username='张三', pwd='qwerqwer', age=18,live=False)
r.save()
print(r.username)

>
create table if not exists user ('username', 'pwd', 'age', 'live') default charset=utf8;
create table if not exists order ('order', 'address', 'money') default charset=utf8;
insert into user value ('张三', 'qwerqwer', 18, False);
张三

猜你喜欢

转载自blog.csdn.net/qq_25672165/article/details/111364597