python——type()metaclass元类和精简ORM框架
Posted 善良的大猪猪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python——type()metaclass元类和精简ORM框架相关的知识,希望对你有一定的参考价值。
1、type()函数
if __name__ == ‘__main__‘: h = hello() h.hello() print(type(hello)) print(type(h))
if __name__ == ‘__main__‘:
h = hello()
h.hello()
print(type(hello))
print(type(h))
Hello, world. <class ‘type‘> <class ‘__main__.Hello‘>
Hello, world.
<class ‘type‘>
<class ‘__main__.Hello‘>
2、metaclass元类
#metaclass 元类 metaclass允许你创建类或者修改类 class Listmetaclass(type): def __new__(cls, name,bases,attrs): attrs[‘add‘] = lambda self,value:self.append(value) #增加了add()方法 return type.__new__(cls,name,bases,attrs) class MyList(list,metaclass=Listmetaclass): pass #__new__()方法接收到的参数依次是: #1、当前准备创建的类的对象; #2、类的名字; #3、类继承的父类集合; #4、类的方法集合。 #元类一般情况不常用,但总会遇到需要通过metaclass修改类定义的。ORM就是一个典型的例子。 #ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象, # 也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。 #要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。
#metaclass 元类 metaclass允许你创建类或者修改类 class Listmetaclass(type): def __new__(cls, name,bases,attrs): attrs[‘add‘] = lambda self,value:self.append(value) #增加了add()方法 return type.__new__(cls,name,bases,attrs) class MyList(list,metaclass=Listmetaclass): pass #__new__()方法接收到的参数依次是: #1、当前准备创建的类的对象; #2、类的名字; #3、类继承的父类集合; #4、类的方法集合。 #元类一般情况不常用,但总会遇到需要通过metaclass修改类定义的。ORM就是一个典型的例子。 #ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象, # 也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。 #要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。
3、精简ORM框架
#开始编写ORM框架 class Field(object): def __init__(self,name,column_type): self.name = name self.column_type = column_type def __str__(self): return ‘<%s:%s>‘%(self.__class__.__name__,self.name) class StringField(Field): def __init__(self,name): super(StringField,self).__init__(name,‘varchar(100)‘) class IntegerField(Field): def __init__(self,name): super(IntegerField,self).__init__(name,‘bigint‘) #下一步,就是编写最复杂的ModelMetaclass了: class ModelMetaclass(type): def __new__(cls, name,bases,attrs): if name == ‘Model‘: #排除掉对Model类的修改; return type.__new__(cls,name,bases,attrs) print(‘Found Model: %s‘%name) mappings = dict() for k,v in attrs.items(): #查找定义的类的所有属性, if isinstance(v,Field): #如果找到一个Field属性, print(‘Found mapping: %s ==> %s‘ % (k, v)) mappings[k] = v #就把它保存到一个__mappings__的dict中 for k in mappings.keys(): attrs.pop(k) #同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性); attrs[‘__mappings__‘] = mappings # 保存属性和列的映射关系 attrs[‘__table__‘] = name # 假设表名和类名一致 把表名保存到__table__中 return type.__new__(cls,name,bases,attrs) #基类Model class Model(dict,metaclass=ModelMetaclass): def __init__(self,**kw): super(Model,self).__init__(**kw) def __getattr__(self, item): #没有找到的属性,就在这里找 try: return self[item] except KeyError: raise AttributeError(r"‘Model‘ object has no attrs :‘%s‘"%item) def __setattr__(self, key, value): self[key] = value def save(self): fields = [] params = [] args = [] for k,v in self.__mappings__.items(): fields.append(v.name) params.append(‘?‘) args.append(getattr(self,k,None)) sql = ‘insert into %s (%s) values (%s)‘ % (self.__table__, ‘,‘.join(fields), ‘,‘.join(params)) print(‘SQL: %s‘ % sql) print(‘ARGS: %s‘ % str(args)) #子类User # 定义类的属性到列的映射: class User(Model): id = IntegerField(‘id‘) name = StringField(‘username‘) email = StringField(‘email‘) password = StringField(‘password‘) age = IntegerField(‘age‘)
#开始编写ORM框架
class Field(object):
def __init__(self,name,column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return ‘<%s:%s>‘%(self.__class__.__name__,self.name)
class StringField(Field):
def __init__(self,name):
super(StringField,self).__init__(name,‘varchar(100)‘)
class IntegerField(Field):
def __init__(self,name):
super(IntegerField,self).__init__(name,‘bigint‘)
#下一步,就是编写最复杂的ModelMetaclass了:
class ModelMetaclass(type):
def __new__(cls, name,bases,attrs):
if name == ‘Model‘: #排除掉对Model类的修改;
return type.__new__(cls,name,bases,attrs)
print(‘Found Model: %s‘%name)
mappings = dict()
for k,v in attrs.items(): #查找定义的类的所有属性,
if isinstance(v,Field): #如果找到一个Field属性,
print(‘Found mapping: %s ==> %s‘ % (k, v))
mappings[k] = v #就把它保存到一个__mappings__的dict中
for k in mappings.keys():
attrs.pop(k) #同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性);
attrs[‘__mappings__‘] = mappings # 保存属性和列的映射关系
attrs[‘__table__‘] = name # 假设表名和类名一致 把表名保存到__table__中
return type.__new__(cls,name,bases,attrs)
#基类Model
class Model(dict,metaclass=ModelMetaclass):
def __init__(self,**kw):
super(Model,self).__init__(**kw)
def __getattr__(self, item): #没有找到的属性,就在这里找
try:
return self[item]
except KeyError:
raise AttributeError(r"‘Model‘ object has no attrs :‘%s‘"%item)
def __setattr__(self, key, value):
self[key] = value
def save(self):
fields = []
params = []
args = []
for k,v in self.__mappings__.items():
fields.append(v.name)
params.append(‘?‘)
args.append(getattr(self,k,None))
sql = ‘insert into %s (%s) values (%s)‘ % (self.__table__, ‘,‘.join(fields), ‘,‘.join(params))
print(‘SQL: %s‘ % sql)
print(‘ARGS: %s‘ % str(args))
#子类User
# 定义类的属性到列的映射:
class User(Model):
id = IntegerField(‘id‘)
name = StringField(‘username‘)
email = StringField(‘email‘)
password = StringField(‘password‘)
age = IntegerField(‘age‘)
当用户定义一个class User(Model)
时,Python解释器首先在当前类User
的定义中查找metaclass
,如果没有找到,就继续在父类Model
中查找metaclass
,找到了,就使用Model
中定义的metaclass
的ModelMetaclass
来创建User
类,也就是说,metaclass可以隐式地继承到子类,但子类自己却感觉不到。
在ModelMetaclass
中,一共做了几件事情:
-
排除掉对Model
类的修改; -
在当前类(比如User
)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个__mappings__
的dict中,同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性); -
把表名保存到__table__
中,这里简化为表名默认为类名。
在Model
类中,就可以定义各种操作数据库的方法,比如save()
,delete()
,find()
,update
等等。
我们实现了save()
方法,把一个实例保存到数据库中。因为有表名,属性到字段的映射和属性值的集合,就可以构造出INSERT
语句。
if __name__ == ‘__main__‘: u = User(id = 12345,name = ‘john‘,email = ‘[email protected]‘,password = ‘666666‘) u.age = 12 u.save()
if __name__ == ‘__main__‘:
u = User(id = 12345,name = ‘john‘,email = ‘[email protected]‘,password = ‘666666‘)
u.age = 12
u.save()
Found Model: User Found mapping: id ==> <IntegerField:id> Found mapping: name ==> <StringField:username> Found mapping: email ==> <StringField:email> Found mapping: password ==> <StringField:password> Found mapping: age ==> <IntegerField:age> SQL: insert into User (id,username,email,password,age) values (?,?,?,?,?) ARGS: [12345, ‘john‘, ‘[email protected]‘, ‘666666‘, 12]
Found Model: User
Found mapping: id ==> <IntegerField:id>
Found mapping: name ==> <StringField:username>
Found mapping: email ==> <StringField:email>
Found mapping: password ==> <StringField:password>
Found mapping: age ==> <IntegerField:age>
SQL: insert into User (id,username,email,password,age) values (?,?,?,?,?)
ARGS: [12345, ‘john‘, ‘[email protected]‘, ‘666666‘, 12]
即使在初始化的时候传进了height参数,依然会被过滤掉,而定义好了到列的映射的类属性age,即使没有赋值,也会被默认为None,并添加到数据库中。
save()
方法已经打印出了可执行的SQL语句,以及参数列表,只需要真正连接到数据库,执行该SQL语句,就可以完成真正的功能。下面入库操作,还有剩下的删改查操作可自行解决。以上是关于python——type()metaclass元类和精简ORM框架的主要内容,如果未能解决你的问题,请参考以下文章
35.Python面向对象元类:type()__metaclass__属性实现简易ORM框架
35.Python面向对象元类:type()__metaclass__属性实现简易ORM框架