簡體   English   中英

使用 cattrs / attrs where attr name does not match keys to create an object

[英]Using cattrs / attrs where attr name does not match keys to create an object

我正在考慮從輸入所有類的完全手動過程轉移到 cattrs / attrs,但需要一些幫助來理解如何實現以下目標。

這是一個示例,但返回的數據會有所不同,有時不會填充所有字段。

data = {
  "data": [
    {
      "broadcaster_id": "123",
      "broadcaster_login": "Sam",
      "language": "en",
      "subscriber_id": "1234",
      "subscriber_login": "Dave",
      "moderator_id": "12345",
      "moderator_login": "Tom",
      "delay": "0",
      "title": "Weekend Events"
    }
  ]
}

@attrs.define
class PartialUser:
    id: int
    login: str

@attrs.define
class Info:
    language: str
    title: str
    delay: int
    broadcaster: PartialUser
    subscriber: PartialUser
    moderator: PartialUser

因此,我了解您將如何構建它,並且它與預期的 1:1 映射完美配合,但是您將如何動態創建 PartialUser 對象,因為名稱與來自 API 的 JSON 響應不同?

instance = cattrs.structure(data["data"][0], Info)

使用轉換器有什么技巧嗎? 這需要為大約 70 個類完成,這就是為什么我認為 cattrs 可以現代化和簡化我正在嘗試做的事情。

謝謝

這是一種可能的解決方案。

這是策略:我們將通過包裝來自定義結構掛鈎。 默認鈎子期望輸入字典中的鍵與類的結構相匹配,但這里不是這種情況。 因此,我們將替換我們自己的結構掛鈎,它會進行一些預處理,然后調用默認掛鈎。

可以像這樣檢索 attrs 類cls的默認掛鈎:

from cattrs import Converter
from cattrs.gen import make_dict_structure_fn

c = Converter()
handler = make_dict_structure_fn(cls, c)

知道了這一點,我們可以這樣實現一個輔助函數:

def group_by_prefix(cls: type, c: Converter, *prefixes: str) -> None:
    handler = make_dict_structure_fn(cls, c)

    def prefix_grouping_hook(val: dict[str, Any], _) -> Any:
        by_prefix = {}
        for key in val:
            if "_" in key and (prefix := (parts := key.split("_", 1))[0]) in prefixes:
                by_prefix.setdefault(prefix, {})[parts[1]] = val[key]
        return handler(val | by_prefix, _)

    c.register_structure_hook(cls, prefix_grouping_hook)

此函數采用 attrs 類cls 、轉換器和前綴列表。 然后它創建一個鈎子並將其注冊到類cls的轉換器。 在內部,它會進行一些預處理以將數據打造成 cattrs 期望的形狀。

以下是如何將它用於Info類:

>>> c = Converter()
>>> group_by_prefix(Info, c, "broadcaster", "subscriber", "moderator")
>>> print(c.structure(data["data"][0], Info))
Info(language='en', title='Weekend Events', delay=0, broadcaster=PartialUser(id=123, login='Sam'), subscriber=PartialUser(id=1234, login='Dave'), moderator=PartialUser(id=12345, login='Tom'))

您可以使用此方法根據需要使解決方案更加詳盡。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM