【问题标题】:Python typing: typed dictionary or defaultdict extending classesPython类型:类型化字典或defaultdict扩展类
【发布时间】:2020-04-18 11:21:05
【问题描述】:

我有一段旧的 python 代码可以解析格式严格的文本文件(存储用于本地化的字符串)。因为结构是分层的,有些元素可能存在也可能不存在,所以程序使用嵌套的defaultdicts 来表示它。比如:

terms = defaultdict(lambda: defaultdict(str)) # dict<key, dict<lang, translation>>

因为这些字典没有类型(因为它们的成员可以是任何类型)并且因为它们是嵌套的,并且因为我需要在该层次结构中添加另一个级别,所以我决定在这个程序中添加类型:

from typing import Tuple, Dict, Set, List, NewType

Key = NewType('Key', str)
Lang = NewType('Lang', str)
Translation = NewType('Translation', str)
PLIndex = NewType('PLIndex', int)

但是,我终其一生都无法弄清楚如何重写上面的 terms = 行以使嵌套的 defaultdicts 键入。

我最终所做的只是将dict 包装到我的类型中,这看起来不太好:

class Forms:
    def __init__(self):
        self.dct: Dict[PLIndex, Translation] = {}

    def __getitem__(self, item: PLIndex) -> Translation:
        return self.dct[item]

    def __setitem__(self, key: PLIndex, value: Translation) -> None:
        self.dct[key] = value


class Translations:
    def __init__(self):
        self.dct: Dict[Lang, Forms] = {}

    def __getitem__(self, item: Lang) -> Forms:
        if item not in self.dct:
            self.dct[item] = Forms()
        return self.dct[item]

    def __setitem__(self, key: Lang, value: Forms) -> None:
        self.dct[key] = value

    def items(self):
        return self.dct.items()


class Terms:
    def __init__(self):
        self.dct: Dict[Key, Translations] = {}

    def __getitem__(self, item: Key) -> Translations:
        if item not in self.dct:
            self.dct[item] = Translations()
        return self.dct[item]

    def __setitem__(self, key: Key, value: Translations) -> None:
        self.dct[key] = value

    def __len__(self):
        return len(self.dct)

    def items(self):
        return self.dct.items()

...

terms = Terms()

有没有办法可以将我的 FormsTranslations 和其他类型声明为 dict/defaultdictNewTypes 并能够以强制执行的方式重写 terms =嵌套字典的正确类型?或者我可以扩展dict/defaultdict(而不是包装它们)并能够强制执行正确的类型?还是有更好的方法?

【问题讨论】:

  • terms: DefaultDict[Key, DefaultDict[Lang, Translation]] = ... 不准确吗?

标签: python types type-hinting


【解决方案1】:

在我看来,包装 dicts 的代码毫无意义(因为它没有添加任何新功能,但您仍然需要维护它),如果可能,我会避免使用它。

现在,以下对我有用:

from collections import defaultdict
from typing import Tuple, Dict, DefaultDict, Set, List, NewType

Key = NewType('Key', str)
Lang = NewType('Lang', str)
Translation = NewType('Translation', str)
PLIndex = NewType('PLIndex', int)

FormsDict = DefaultDict[PLIndex, Translation]
TranslationsDict = DefaultDict[Lang, FormsDict]
TermsDict = DefaultDict[Key, TranslationsDict]

terms: TermsDict = defaultdict(         # TermsDict
    lambda: defaultdict(                # TranslationsDict
        lambda: defaultdict(            # FormsDict
            lambda: Translation("")     # Default value "" (as Translation)
        )
    )
)

我已经用mypy --strict 对此进行了测试,它通过了验证。将其与defaultdict 一起使用并且仍然通过验证,看来您将需要cast

from typing import cast

terms[Key("key1")].update(
    cast(TranslationsDict, {
        Lang("en_GB.UTF-8"): cast(FormsDict, {
            PLIndex(100): Translation("key1")
        })
    })
)

print(terms)

输出:

defaultdict(<function <lambda> at 0x107d31cb0>, {
    'key1': defaultdict(<function <lambda>.<locals>.<lambda> at 0x107d31d40>, {
        'en_GB.UTF-8': {100: 'key1'}})})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    相关资源
    最近更新 更多