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])
# 春田