# -*- coding: utf-8 -*-
# @Author : pengj <ugeg@163.com>
# @Time : 2019/1/5 16:40
# @File : MyORM.py
import numbers
class Field:
pass
class CharField(Field):
# 数据描述符
# 好处在于可以在各方法中校验传入值的合理性
def __init__(self, col_name, max_length):
if col_name is None or not isinstance(col_name, str):
raise ValueError("col_name must be given as str")
if max_length is None or not isinstance(max_length, numbers.Integral):
raise ValueError("max_length must be given as int")
self._col_name = col_name
self._max_length = max_length
def __get__(self, instance, owner):
# return getattr(instance, self._col_name)
return instance.fields[self._col_name]
def __set__(self, instance, value):
# 这里如果col_name和数据描述符对应的名字一样的话,如name=CharField(col_name="name",10)
# 用setattr(instance, self._col_name, value)即user.name=value会再次进入此__set__方法,导致无限递归
instance.fields[self._col_name] = value
class IntField(Field):
def __init__(self, col_name, min_length, max_length):
self._col_name = col_name
self._min_length = min_length
self._max_length = max_length
def __get__(self, instance, owner):
return instance.fields[self._col_name]
def __set__(self, instance, value):
if value is None or (not isinstance(value, numbers.Integral)):
raise ValueError("value must be given as int")
instance.fields[self._col_name] = value
class ModelMetaClass(type):
def __new__(cls, cls_name, base_class, attrs):
if cls_name == "Model":
return super().__new__(cls, cls_name, base_class, attrs)
fields = {}
for k, v in attrs.items():
if isinstance(v, Field):
fields[k] = v
attrs["fields"] = fields
_meta = {}
attrs_meta = attrs.get("Meta", None)
if attrs_meta is not None and isinstance(attrs_meta, type):
_meta["tb_name"] = getattr(attrs_meta, "tb_name", cls_name)
del attrs["Meta"]
else:
_meta["tb_name"] = cls_name.lower()
attrs["_meta"] = _meta
return super().__new__(cls, cls_name, base_class, attrs)
class Model(metaclass=ModelMetaClass):
def __init__(self, **kwargs):
self.fields = {}
for k, v in kwargs.items():
setattr(self, k, v)
# def more_func(self):
# pass
class User(Model):
name = CharField(col_name="name", max_length=10)
sex = CharField(col_name="sex", max_length=1)
age = IntField(col_name="age", min_length=1, max_length=10)
class Meta:
tb_name = "User"
class Company(Model):
name = CharField(col_name="name", max_length=10)
address = CharField(col_name="address", max_length=1)
# class Meta:
# tb_name = "Company"
if __name__ == "__main__":
user = User(name="boy1", age=5, sex="男")
user1 = User(name="girl1", age=6, sex="女")
company = Company(name="com", address="China")
print(User.__dict__)
print(user.__dict__)
print(user1.__dict__)
print(Company.__dict__)
print(company.__dict__)
输出
{'__module__': '__main__', 'name': <__main__.CharField object at 0x0000013ACD432828>, 'sex': <__main__.CharField object at 0x0000013ACD432A20>, 'age': <__main__.IntField object at 0x0000013ACD432AC8>, 'fields': {'name': <__main__.CharField object at 0x0000013ACD432828>, 'sex': <__main__.CharField object at 0x0000013ACD432A20>, 'age': <__main__.IntField object at 0x0000013ACD432AC8>}, '_meta': {'tb_name': 'User'}, '__doc__': None}
{'fields': {'name': 'boy1', 'age': 5, 'sex': '男'}}
{'fields': {'name': 'girl1', 'age': 6, 'sex': '女'}}
{'__module__': '__main__', 'name': <__main__.CharField object at 0x0000013ACD432B00>, 'address': <__main__.CharField object at 0x0000013ACD432EB8>, 'fields': {'name': <__main__.CharField object at 0x0000013ACD432B00>, 'address': <__main__.CharField object at 0x0000013ACD432EB8>}, '_meta': {'tb_name': 'company'}, '__doc__': None}
{'fields': {'name': 'com', 'address': 'China'}}
参考:
Python高级编程和异步IO并发编程
Python描述符 (descriptor) 详解-属性查询优先级