如何将 Python 数据类转换为字符串字面量字典?

给定如下数据类:

class MessageHeader(BaseModel):
    message_id: uuid.UUID

    def dict(self, **kwargs):
        return json.loads(self.json())

当我在 dict 上调用 MessageHeader 时,我想得到一个字符串字面量字典。字典的期望结果如下:

{'message_id': '383b0bfc-743e-4738-8361-27e6a0753b5a'}

我想避免使用像 pydantic 这样的第 3 方库,并且我不想使用 json.loads(self.json()) 因为有额外的往返

有没有更好的方法将数据类转换为具有上述字符串文字的字典?

stack overflow How to convert Python dataclass to dictionary of string literal?
原文答案
author avatar

接受的答案

您可以使用 dataclasses.asdict

from dataclasses import dataclass, asdict

class MessageHeader(BaseModel):
    message_id: uuid.UUID

    def dict(self):
        return {k: str(v) for k, v in asdict(self).items()}

如果您确定您的类只有字符串值,则可以完全跳过字典理解:

class MessageHeader(BaseModel):
    message_id: uuid.UUID

    dict = asdict

答案:

作者头像

对于绝对的 **pure, unadulterated speed****boundless efficiency** ,它们甚至可能导致 Chuck Norris 等人停下来,无助地敬畏地看着,我谦虚地推荐这种带有 remarkably well planned-out__dict__ 方法:

def dict(self):
    _dict = self.__dict__.copy()
    _dict['message_id'] = str(_dict['message_id'])
    return _dict

万一现在有人在座位边缘摇摇晃晃(我 know ,这真是令人难以置信, breakthrough 级别的东西) - 我已经通过下面的 timeit 模块添加了我的个人时间,即应该希望在事物的性能方面有更多的了解。

仅供参考,纯 __dict__ 的方法不可避免地 muchdataclasses.asdict() 快。

注意:尽管 __dict__ 在这种特殊情况下效果更好,但 dataclasses.asdict() 对于复合字典可能会更好,例如具有嵌套数据类的字典,或具有可变类型的值,例如 dict 或 {JXM= }。

list

我的 Windows 11 PC 上的结果:

from dataclasses import dataclass, asdict, field
from uuid import UUID, uuid4

@dataclass
class MessageHeader:
    message_id: UUID = field(default_factory=uuid4)
    string: str = 'a string'
    integer: int = 1000
    floating: float = 1.0

    def dict1(self):
        _dict = self.__dict__.copy()
        _dict['message_id'] = str(_dict['message_id'])
        return _dict

    def dict2(self):
        return {k: str(v) if k == 'message_id' else v
                for k, v in self.__dict__.items()}

    def dict3(self):
        return {k: str(v) if k == 'message_id' else v
                for k, v in asdict(self).items()}

if __name__ == '__main__':
    from timeit import timeit

    header = MessageHeader()

    n = 10000
    print('dict1():  ', timeit('header.dict1()', number=n, globals=globals()))
    print('dict2():  ', timeit('header.dict2()', number=n, globals=globals()))
    print('dict3():  ', timeit('header.dict3()', number=n, globals=globals()))

    print()

    dict__ = header.dict1()
    print(dict__)

    asdict__ = header.dict3()
    print(asdict__)

    assert isinstance(dict__['message_id'], str)
    assert isinstance(dict__['integer'], int)

    assert header.dict1() == header.dict2() == header.dict3()
作者头像

使用 dataclasses.fields 创建字段和值的浅表副本。

from dataclasses import dataclass, fields
import uuid

@dataclass
class MessageHeader:
    message_id: uuid.UUID
    other_string: str

    def dict(self):
        return {field.name: str(getattr(self, field.name)) for field in fields(self)}

message_header = MessageHeader(uuid.uuid4(), "test_str")
print(message_header.dict())