Pyparsing中DelimitedList与Dict联用为何如此繁琐?
Pyparsing:分隔列表转字典的简洁写法?
背景:DelimitedList与Dict的基础用法
Pyparsing提供ParseElementEnhance的子类DelimitedList,用于解析(通常是逗号分隔的)列表:
>>> kv_element = pp.Word(pp.alphanums) >>> kv_list = pp.DelimitedList(kv_element) >>> kv_list.parse_string('red, green, blue') ParseResults(['red', 'green', 'blue'], {})
同时它还提供TokenConverter的子类Dict,可将重复表达式转换为字典:
>>> key = value = pp.Word(pp.alphanums) >>> kv_pair = key + pp.Suppress("=") + value >>> kv_dict = pp.Dict(pp.Group(kv_pair)[...]) >>> kv_dict.parse_string('R=red G=green B=blue') ParseResults([ ParseResults(['R', 'red'], {}), ParseResults(['G', 'green'], {}), ParseResults(['B', 'blue'], {}) ], {'R': 'red', 'G': 'green', 'B': 'blue'})
问题:结合二者的繁琐之处
但将这两个类结合使用时,写法会变得十分繁琐。虽然能构建出从分隔列表解析字典的ParserElement,但相比单独使用要多做两步:
- 重新定义
DelimitedList,让它输出Group()包裹的结果 - 构造
Dict()时要重复DelimitedList的定义,才能通过类型检查1
示例代码:
>>> kv_pair = key + pp.Suppress("=") + value >>> kv_pairlist = pp.DelimitedList(pp.Group(kv_pair)) >>> kv_pairdict = pp.Dict(kv_pairlist[...]) >>> kv_pairdict.parse_string('R=red, G=green, B=blue') ParseResults([ ParseResults(['R', 'red'], {}), ParseResults(['G', 'green'], {}), ParseResults(['B', 'blue'], {}) ], {'R': 'red', 'G': 'green', 'B': 'blue'})
这种写法感觉像是在定义一个解析器,从一系列单元素分隔列表(每个列表包含一个键值对)中创建字典(我不确定内部是否真的如此运作)。
当我想表达“匹配一个包含多组键值对的分隔列表”这个意图时,总感觉是在和API较劲。更气人的是,kv_pairdict = pp.Dict(kv_pairlist)在功能上和上面的代码完全一致,但会触发类型检查错误。
提问
在Pyparsing的API里,有没有更简洁的方式来定义这个解析器?如果没有,这是我的设计思路有问题、Pyparsing的API存在不足,还是其他原因?
(是不是我搞反了定义顺序?DelimitedList(Dict(Group(kv_pair)[1, ...]))也能运行,但在我看来逻辑是颠倒的。不过这种写法几乎不需要和API较劲,难道是我的理解错了?)
注释
- (否则,至少在VSCode中会弹出如下不合理的提示:)
No overload variant of "dict" matches argument type
"DelimitedList" (mypycall-overload)Possible overload variants:
def [_KT, _VT] __init__(self) -> dict[_KT, _VT] def [_KT, _VT] __init__(self, **kwargs: _VT) -> dict[str, _VT] def [_KT, _VT] __init__(self, SupportsKeysAndGetItem[_KT, _VT], /) -> dict[_KT, _VT] def [_KT, _VT] __init__(self, SupportsKeysAndGetItem[str, _VT], /, **kwargs: _VT) -> dict[str, _VT] def [_KT, _VT] __init__(self, Iterable[tuple[_KT, _VT]], /) -> dict[_KT, _VT] def [_KT, _VT] __init__(self, Iterable[tuple[str, _VT]], /, **kwargs: _VT) -> dict[str, _VT] def [_KT, _VT] __init__(self, Iterable[list[str]], /) -> dict[str, str] def [_KT, _VT] __init__(self, Iterable[list[bytes]], /) -> dict[bytes, bytes]mypy(note)
内容的提问来源于stack exchange,提问作者FeRD
相关产品推荐
相关产品推荐

