元类
python中所有东西都是对象,包括类也是对象,创建类的类就叫做元类,参考文章深刻理解元类
一个实例
def upper_attr(class_name,class_parents,class_attr):
new_attr={}
for name,value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()]=value
return type(class_name,class_parents,new_attr)
class Foo(object,metaclass=upper_attr):
bar="bip"
print(hasattr(Foo,"bar"))
print(hasattr(Foo,"BAR"))
f=Foo()
print(f.BAR)
创建一个类的时候如果没有metaclass参数,就直接用type创建类,但是有了这个参数之后,去到这个函数引用,把类名Foo传递给class_name,把object传递给class_parents,把其他类属性传递给class_attr。返回type(class_name,class_parents,class_attr)
面向对象改造
class UpperAttrMetaClass(type):
def __new__(cls, class_name,class_parents,class_attr):
new_attr={}
for name,value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()]=value
return type(class_name,class_parents,new_attr)
class Foo(object,metaclass=UpperAttrMetaClass):#指定一个元类
bar="bip"
print(hasattr(Foo,"bar"))
print(hasattr(Foo,"BAR"))
f=Foo()
print(f.BAR)
以上代码实现的是将创建类的属性都变成大写
orm本质
其本质是通过调用对象实现同等的sql语句
- ex:insert into 表 字段列表 value 字段值列表==> u=user(字典) u.save()
orm实现
class ModelMetaClass(type):
def __new__(cls, name, bases, attrs):
mappings = dict()
for k, v in attrs.items():
if isinstance(v, tuple):
mappings[k] = v
for k in mappings.keys():
attrs.pop(k)
attrs['__mappings__'] = mappings
attrs['__table__'] = name
return type.__new__(cls,name,bases,attrs)
class User(metaclass=ModelMetaClass):
uid=('uid',"int unsigned")
name=('username',"barchar(30)")
email=('email',"varchar(30)")
password=('password',"varchar(30)")
def __init__(self,**kwargs):
for name,value in kwargs.items():
setattr(self,name,value)
def save(self):
fields=[]
args=[]
for k,v in self.__mappings__.items():
fields.append(v[0])
args.append(getattr(self,k,None))
args_temp=list()
for temp in args:
if isinstance(temp,int):
args_temp.append(str(temp))
elif isinstance(temp,str):
args_temp.append("""'%s'"""%temp)
sql='insert into %s (%s) values (%s)'%(self.__table__,','.join(fields),\
','.join(str(i) for i in args_temp))
print(sql)
u=User(uid=122,name="zhangyue",email="xxx",password="pass")
u.save()
思想:
用元类来创建User类,uid、name、email、password等属性。传递到元类,元类接受之后把他们转换成字典,用__mappings__保存,表明也就是User用__table__保存,用pop删除原来的属性,使字典为新的属性,这样做的目的是为了匹配sql语句的表名,和字段名
#运行结果
author:specyue@mail.ustc.edu.cn
github:https://github.com/zhangyuespec/mini_web