当前位置:
首页 > temp > 简明python教程 >
-
PythonI/O进阶学习笔记_7.python动态属性,__new__和__init__和元类编程(下)(4)
可以看见args的列传进去的基本就是name(类名)、bases、attrs(属性dict)。将参数用这三个变量代替。与django中设置的变量一致。
对传递进去的attrs进行操作,如果是在User内定义的charfield、interfield这种类型的字段,直接用__new__生成对应的key、value。
但是对User类中定义的meta这类属性,对里面的一些属性的定义就需要做对应的处理。
又因为我们想把InterField、CharField这种属性描述符作为key,value存储,meta属性里的一些字段做特定处理,所以我们让各种属性描述符类继承同一个Field来判断是否都是Field类来做统一key value处理。
在User继承了改动过的元类之后。再User类中定义init,就能再pycharm中看到User中的变量。
class Field: pass class ModelMetaClass(type): def __new__(cls, name, bases, attrs, **kwargs): fields=dict() for key,value in attrs.items(): if isinstance(value,Field): fields[key]=value attrs_meta=attrs.get("Meta",None) _meta={} db_table=name.lower() if attrs_meta is not None: table=getattr(attrs_meta,"db_table",None) if table is not None: db_table=table attrs["db_table"]=db_table attrs["_meta"]=attrs_meta attrs["fields"]=fields del fields["Meta"] return super().__new__(cls,name, bases, attrs,**kwargs)
debug之后的效果:
c.定义User类的父类
但是在我们实际应用的时候,不可能每个User去定义__init__函数,save函数这样,所以我们就用一个modle父类,让User这些类来继承。
需要注意的是:
如果定义一个父类BaseModel,需要在BaseModel继承的元类中判断如果传进来的name是BaseModel,就直接__new__就可以了。因为在BaseModel中,是没有定义fields这些东西的。
并且在父类中,定义好save方法。
最后完整的代码为:
import numbers class Field: pass class InterField(Field): def __init__(self,db_column=None,min_value=None,max_value=None): self._min_value=min_value self._max_value=max_value self.db_column=db_column if self._min_value is not None: if not isinstance(self._min_value,numbers.Integral): raise ValueError("Value Must be Intergral") elif self._min_value < 0: raise ValueError("Value Must large than 0") if self._max_value is not None: if not isinstance(self._max_value,numbers.Integral): raise ValueError("Value must be Intergral") elif self._max_value <0 : raise ValueError("Value must large than 0") if max_value < min_value: raise ValueError("Max must large than min ") def __get__(self, instance, owner): return self._value def __set__(self, instance, value): if not isinstance(value,numbers.Integral): raise ValueError("Not intergral") self._value=value class CharField(Field): def __init__(self,db_column=None,max_length=None): self.db_column=db_column self._max_length=max_length if not max_length: raise ValueError("You must special the charfield length") def __get__(self, instance, owner): return self._value def __set__(self, instance, value): self._value=value if len(value) > self._max_length: raise ValueError("Value's length must less than max length") class ModelMetaClass(type): def __new__(cls, name, bases, attrs, **kwargs): if name=="BaseModel": super().__new__(cls,name,bases,attrs,**kwargs) fields=dict() for key,value in attrs.items(): if isinstance(value,Field): fields[key]=value attrs_meta=attrs.get("Meta",None) _meta={} db_table=name.lower() if attrs_meta is not None: table=getattr(attrs_meta,"db_table",None) if table is not None: db_table=table attrs["db_table"]=db_table attrs["_meta"]=attrs_meta attrs["fields"]=fields if attrs_meta: del attrs["Meta"] return super().__new__(cls,name, bases, attrs,**kwargs) class ModelBase(metaclass=ModelMetaClass): def __init__(self,*args,**kwargs): for key,value in kwargs.items(): setattr(self,key,value) return super().__init__() def save(self): fields=[] values=[] for key,value in self.fields.items(): db_column=value.db_column if db_column is None: db_column=key.lower() fields.append(db_column) value=getattr(self,key) values.append(str(value)) sql = "insert {db_table}({fields}) value({values})".format(db_table=self._meta.db_table,fields=",".join(fields),values=",".join(values)) pass class User(ModelBase): name=CharField(max_length=10) age=InterField(min_value=0,max_value=100) class Meta: db_table="user" def _test(self): print("_test:",self.age) if __name__=="__main__": user=User() user.name="bobby" user.age=23 user._test() user.save()