元类和ORM
新式类和旧式类
定义
- 新式类:继承了object的类才是新式类,Python 3.x中默认继承object,因此都是新式类。
- 旧式类:继承了instance的类是旧式类(经典类),Python 2.x只有显式继承了object才是新式类。
区别:
- 新式类保持class与type的统一,通过__class__与type()访问的结果是一致的。也就是说新式类统一了类(class)和类型(type)的概念,而旧式类的类型(type)继承自instance类型,因此旧式类的类(class)和类型(type)是不一样的。
- 新式类是采用广度优先搜索,旧式类采用深度优先搜索。即:旧式类先深入继承树左侧,再返回,开始找右侧;新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动
- 新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中
- 新式类增加了__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);
张三