Last active
August 7, 2020 07:07
-
-
Save c1ay/ec5eb0199b1f98910c6d32c8db4fc44a to your computer and use it in GitHub Desktop.
使用python 类型标注的解析字段,适用于rpc调用,字段懒加载
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import typing | |
from abc import ABCMeta | |
INSTANCE_ATTR = 'instance_attr' | |
class UndefinedType: | |
def __repr__(self): | |
return 'UndefinedType' | |
Undefined = UndefinedType() | |
class ModelField: | |
def __init__(self, name: str, type_: typing.Type, default: typing.Any = None): | |
self.name = name | |
self.type_ = type_ | |
self.default = default | |
@classmethod | |
def infer(cls, name, value, type_): | |
if value is Undefined: | |
default = None | |
else: | |
default = value | |
return cls(name=name, type_=type_, default=default) | |
class DynamicMetaclass(ABCMeta): | |
__fields__ = typing.Dict[str, typing.Any] | |
def __new__(mcs, name, bases, namespace, **kwargs): | |
fields: typing.Dict[str, ModelField] = {} | |
annotations = namespace.get('__annotations__', {}) | |
for ann_name, ann_type in annotations.items(): | |
value = namespace.get(ann_name, Undefined) | |
fields[ann_name] = ModelField.infer(name=ann_name, value=value, type_=ann_type) | |
namespace.update({'__fields__': fields}) | |
fields_properties = {} | |
for field in fields.values(): | |
origin_get_func = namespace.get(f'resolve_{field.name}', Undefined) | |
fields_properties[field.name] = property(make_get_func(field, origin_get_func), | |
make_set_func(field)) | |
namespace.update(**fields_properties) | |
namespace.update({'fields': fields}) | |
return super().__new__(mcs, name, bases, namespace, **kwargs) | |
class BaseModel(metaclass=DynamicMetaclass): | |
def dict(self, include: typing.List = None): | |
fields = self.fields | |
if include: | |
fields = set(fields) & set(include) | |
return {k: getattr(self, k) for k in fields} | |
def make_get_func(field, origin_get_func): | |
def get_func(self): | |
attr_name = field.name | |
if attr_name in self.__dict__: | |
return self.__dict__[attr_name] | |
if origin_get_func is not Undefined: | |
return origin_get_func(self) | |
# try to get from instance | |
instance_attr = getattr(self, INSTANCE_ATTR, 'instance') | |
instance = getattr(self, instance_attr, None) | |
if instance: | |
return getattr(instance, attr_name, field.default) | |
return field.default | |
return get_func | |
def make_set_func(field): | |
def set_func(self, value): | |
attr_name = field.name | |
self.__dict__[attr_name] = value | |
return set_func |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
使用方法: