【问题标题】:Dataclass object property alias数据类对象属性别名
【发布时间】:2021-07-04 04:09:22
【问题描述】:

我正在做一个项目来了解更多关于使用 Python dataclasses 的信息。具体来说,我试图将 API 响应表示为 dataclass 对象。但是,由于 API 响应的结构,我遇到了问题。

这是来自 API 的示例响应:

{
    "@identifier": "example",
    "@name": "John Doe",
}

某些字段的名称中有特殊字符。这意味着我无法直接映射 dataclass 的属性,因为属性名称中不允许使用特殊字符,例如 @ (SyntaxError)。

有没有办法为我的dataclass 属性定义别名,以便我可以将 API 响应直接映射到 dataclass 对象?还是需要先清理响应?

【问题讨论】:

  • 不是对您问题的直接回答,但您可以考虑使用 pydantic 库,如果别名无效,您可以在字段中添加别名

标签: python python-dataclasses


【解决方案1】:

添加一个“干净”函数并用它包装 API 响应字典。

该解决方案不需要外部库。

from dataclasses import dataclass

api_response = {
    "@identifier": "example",
    "@name": "John Doe",
}


def clean(data: dict) -> dict:
    def _clean(key):
        return key[1:]

    result = {}
    for k, v in data.items():
        result[_clean(k)] = v
    return result


@dataclass
class Response:
    name: str
    identifier: str


res = Response(**clean(api_response))
print(res)

输出

Response(name='John Doe', identifier='example')

【讨论】:

    【解决方案2】:

    事实上,不仅对象的属性名称中不能有特殊字符,变量也不能有特殊字符。在 Python 中,变量名中只允许使用字符 a-zA-Z0-9_,如果你尝试做这样的事情(v@r = 3),正如你所说,你会得到SyntaxError .另请注意,变量名称中允许使用数字,但不能在变量的开头:

    # Ok
    test0 = 'Hello World!'
    # SyntaxError
    0test = 'Goodbye Moonman!'
    

    我建议更改属性名称,从字典键中删除特殊字符,例如 @。因为最后,您需要在属性名称中添加特殊字符是为了什么?

    也许您可以使用 Python 对象的 __getitem____setitem__ 魔术方法来解决一些问题,如下所示:

    class Object():
        def __init__(self, props):
            self._props = props
        def __getitem__(self, i):
            return self._props[i]
    

    所以你现在可以使用这个了:

    x = {'Hello': 'World!', '@oodby&': 'Moonman!'}
    x = Object(x)
    
    print(x['Hello'])      # World!
    print(x['@oodby&'])    # Moonman!
    

    也许这不是您正在寻找的,尽管这可能有其优势。例如,您可以定义一些类方法来使用self._props

    更多关于__getitem__here:)

    【讨论】:

    • 谢谢。我同意在您可以完全控制数据结构的情况下,从源头清理数据(从字典中删除特殊字符)是可行的方法。但是,就我而言,我正在使用一个 API,其中源数据的结构超出了我的控制范围。我很好奇 Python dataclasses 是否有这种情况的可供性(例如字段别名)或者我是否需要先清理数据。
    • @thijsfranck 看看我最近的编辑 :)
    • “在 Python 中,变量名中只允许使用字符 a-z、A-Z、0-9 和 _”——这不是真的。 Python3 支持相当广泛的 unicode 字符(但不支持@
    【解决方案3】:

    dataclasses-json,可以给属性起别名:

    from dataclasses import dataclass, field
    from dataclasses_json import config, dataclass_json
    
    
    @dataclass_json
    @dataclass
    class Person:
        magic_name: str = field(metadata=config(field_name="@name"))
        magic_id: str = field(metadata=config(field_name="@identifier"))
    
    
    p = Person.from_json('{"@name": "John Doe", "@identifier": "example"}')
    print(p.magic_name)
    print(p.to_json())
    

    输出:

    John Doe
    {"@name": "John Doe", "@identifier": "example"}
    

    【讨论】:

      猜你喜欢
      • 2013-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多