开发者社区> 问答> 正文

Python输入:输入字典或defaultdict扩展类

我有一段旧的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()

有没有一种方法我可以宣布我的Forms,Translations和其他类型的只是NewTypeS代表dict/ defaultdict并能够改写terms =的,将强制执行正确类型的嵌套字典的方法吗?还是可以扩展dict/ defaultdict(而不是包装它们)并能够强制使用正确的类型?还是完全有更好的方法?

展开
收起
几许相思几点泪 2019-12-29 19:34:10 929 0
1 条回答
写回答
取消 提交回答
  • 在我看来,包装字典似乎毫无意义(因为它没有添加任何新功能,但您仍然必须对其进行维护),如果可能,我会避免使用。

    现在,以下内容对我有用:

    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'}})})
    
    2019-12-29 19:34:48
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
From Python Scikit-Learn to Sc 立即下载
Data Pre-Processing in Python: 立即下载
双剑合璧-Python和大数据计算平台的结合 立即下载