[英]Decorator to Nested List of Dataclass in Python
我想为数据类创建一个字典,其中包含作为属性的数据类列表
这是我想要实现的一个例子:
from typing import List
from dataclasses import dataclass
@dataclass
class level2:
key21: int
key22: int
@nested_dataclass
class level1:
key1: int
key2: List[level2]
data = {
'key1': value1,
'key2': [{
'key21': value21,
'key22': value22,
}]
}
my_object = level1(**data)
print(my_object.key2[0].key21) #should print value21
我发现的最接近的装饰器是这个,但它不适用于数据类列表: 在 Python 中创建嵌套数据类对象
def is_dataclass(obj):
"""Returns True if obj is a dataclass or an instance of a
dataclass."""
_FIELDS = '__dataclass_fields__'
return hasattr(obj, _FIELDS)
def nested_dataclass(*args, **kwargs):
def wrapper(cls):
cls = dataclass(cls, **kwargs)
original_init = cls.__init__
def __init__(self, *args, **kwargs):
for name, value in kwargs.items():
field_type = cls.__annotations__.get(name, None)
if is_dataclass(field_type) and isinstance(value, dict):
new_obj = field_type(**value)
kwargs[name] = new_obj
original_init(self, *args, **kwargs)
cls.__init__ = __init__
return cls
return wrapper(args[0]) if args else wrapper
你将如何修改这个装饰器或创建一个可以完成这项工作的装饰器? (我在建筑装饰方面的经验为零)
非常感谢任何评论/代码。 谢谢
好的,所以我稍微更改了装饰器,但它非常特定于此处提供的示例。 主要问题是您的List[level2]
字段不是dataclass
。 所以为了解决这个问题,我玩了一会儿,注意到有一个args属性可以告诉你列表中的嵌套类型。 我以前从未使用过数据类(除了 pydantic)所以也许那里有更好的答案
def nested_dataclass(*args, **kwargs):
def wrapper(cls):
cls = dataclass(cls, **kwargs)
original_init = cls.__init__
def __init__(self, *args, **kwargs):
for name, value in kwargs.items():
field_type = cls.__annotations__.get(name, None)
if hasattr(field_type, '__args__'):
inner_type = field_type.__args__[0]
if is_dataclass(inner_type):
new_obj = [inner_type(**dict_) for dict_ in value]
kwargs[name] = new_obj
original_init(self, *args, **kwargs)
cls.__init__ = __init__
return cls
return wrapper(args[0]) if args else wrapper
@dataclass
class level2:
key21: int
key22: int
@nested_dataclass
class level1:
key1: int
key2: List[level2]
data = {
'key1': 1,
'key2': [{
'key21': 21,
'key22': 22,
},
{
'key21': 23,
'key22': 24
}]
}
my_object = level1(**data)
print(my_object.key2[0].key21) #should print 21
print(my_object.key2[1].key21) #should print 23
@nested_dataclass
class random:
key1: int
key2: List[int]
random_object = random(**{'key1': 1, 'key2': [1,2,3]})
print(random_object.key2) # prints [1,2,3]
进一步嵌套
@nested_dataclass
class level3:
key3: List[level1]
level3(**{'key3': [data]})
输出:
level3(key3=[level1(key1=1, key2=[level2(key21=21, key22=22), level2(key21=23, key22=24)])])
pip 安装验证-dc
ValidatedDC: https : //github.com/EvgeniyBurdin/validated_dc
from dataclasses import dataclass
from typing import List, Union
from validated_dc import ValidatedDC
@dataclass
class Level2(ValidatedDC):
key21: int
key22: int
@dataclass
class Level1(ValidatedDC):
key1: int
key2: List[Level2]
data = {
'key1': 1,
'key2': [{
'key21': 21,
'key22': 22,
}]
}
my_object = Level1(**data)
assert my_object.key2[0].key21 == 21
# ----------------------------------
@dataclass
class Level1(ValidatedDC):
key1: int
key2: Union[Level2, List[Level2]]
my_object = Level1(**data) # key2 - list
assert my_object.key2[0].key21 == 21
data['key2'] = {
'key21': 21,
'key22': 22,
}
my_object = Level1(**data) # key2 - dict
assert my_object.key2.key21 == 21
这不提供如何更改装饰器,如果您不想使用任何 3rd 方包,请忽略此答案。 但我认为pydantic
可以做你想做的。 我建议的唯一原因是,当它被声明为列表时,它不允许您错误地将key2
作为字典。
from typing import List
from pydantic import BaseModel
class level2(BaseModel):
key21: int
key22: int
class level1(BaseModel):
key1: int
key2: List[level2]
data = {
'key1': 1,
'key2': [{
'key21': 21,
'key22': 22,
}]
}
my_object = level1(**data)
print(my_object.key2[0].key21) # prints 21
如果你真的想从key2
直接访问key21
那么
class level1(BaseModel):
key1: int
key2: level2 # Not a list
data = {
'key1': 1,
'key2': {
'key21': 21,
'key22': 22,
}
}
my_object = level1(**data)
print(my_object.key2.key21) # prints 21
如果您的目标是成功地让装饰器工作,请再次忽略这一点。 否则安装 pydantic 不会受到伤害:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.