用于实现选择类型的Python数据类

2024-04-18 00:34:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一组数据类,比如:

    from dataclasses import dataclass, asdict, InitVar

    @dataclass
    class Item:  
        name: str = None
        identifier: int = None
        
    @dataclass
    class Container:
        item: Item
        cid: int
        cname: str = None
    

当我这样做时:

c = Container(Item(name="item-1"), cid=10)
asdict(c)

我得到:

{'item': {'name': 'item-1', 'identifier': None},'cid': 10,'cname': None}

但在我的模式中,项是一种“选择”类型,因此我只想在“asdict”中包含“name”或“identifier”,这取决于实际设置的是哪一个(仅针对项类型)

比如:

{'item': {'name': 'item-1'},'cid': 10,'cname': None}

或:

{'item': {'identifier': 'id-1'},'cid': 10,'cname': None}

我的原始代码更加复杂,关系更加嵌套,因此我正在寻找一种可以应用于特定数据类的解决方案。我试图操纵__dict__来在__post_init__中添加属性,但没有成功。例如,我试过了

from dataclasses import dataclass, asdict, InitVar

@dataclass
class Item:  
    name: InitVar[str] = None
    identifier: InitVar[int] = None
        
    def __post_init__(self, name, identifier):
        if name:
            self.name = name
        elif identifier:
            self.identifier = identifier
        print(self.__dict__)
        
    
@dataclass
class Container:
    item: Item
    identifier: int
    cname: str = None
    

c = Container(Item(name="item-1"), cid=10)
asdict(c)

但那是印刷品

{'item': {}, 'cid': 10, 'cname': None}

Tags: nameselfnonecontaineritemclassintcname
2条回答

这可能不是您想要的,但是在这个时候,当您想要一个dataclass的定制的dict表示时,唯一的方法是编写您自己的.asdict方法

这里有一个建议的起点(可能需要调整):

from dataclasses import dataclass, asdict


@dataclass
class DataclassAsDictMixin:
    def asdict(self):
        d = asdict(self)
        for field, value in ((f,v) for f,v in vars(self).items() if f in d):
            try:
                value = value.asdict()
            except AttributeError:
                pass
            else:
                d.update([(field, value)])
        return d


@dataclass
class Item:  
    name: str = None
    identifier: int = None

    def asdict(self):
        d = asdict(self)
        for k,v in d.copy().items():
            if v is None:
                del d[k]
        return d

@dataclass
class Container(DataclassAsDictMixin):
    item: Item
    cid: int
    cname: str = None


if __name__ == "__main__":
    c1 = Container(Item(name="item-1"), cid=10)
    assert c1.asdict() == {'item': {'name': 'item-1'}, 'cid': 10, 'cname': None}
    c2 = Container(Item(identifier="id-1"), cid=10)
    assert c2.asdict() == {'item': {'identifier': 'id-1'}, 'cid': 10, 'cname': None}

我没有使用值列表对其进行测试,但请尝试以下方法:

from copy import copy
from dataclasses import dataclass, fields

from validated_dc import ValidatedDC


@dataclass
class Base(ValidatedDC):

    def is_correct_value(self, value):

        return True

    def as_dict(self):

        result = {}
        nested = tuple(self.get_nested_validated_dc())

        for field in fields(self):
            value = copy(getattr(self, field.name))

            if isinstance(value, list):
                for item in value:
                    if isinstance(item, nested):
                        item = item.as_dict()

            if isinstance(value, nested):
                value = value.as_dict()

            if self.is_correct_value(value):
                result[field.name] = value

        return result


@dataclass
class ItemBase(Base):

    def is_correct_value(self, value):

        return False if value is None else True


@dataclass
class Item(ItemBase):

    name: str = None
    identifier: int = None


@dataclass
class Container(Base):

    item: Item
    cid: int
    cname: str = None


c = Container(Item(name="item-1"), cid=10)
assert c.as_dict() == {'item': {'name': 'item-1'}, 'cid': 10, 'cname': None}

ValidatedDC:https://github.com/EvgeniyBurdin/validated_dc

相关问题 更多 >

    热门问题