从命名空间创建命名元组?

3

我该如何从Namespace初始化一个namedtuple

import collections
import argparse

nt=collections.namedtuple("nt",["foo","bar"]) # _NOT_ "baz"!
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
parser.add_argument('--bar')
parser.add_argument('--baz')
args = parser.parse_args(...)

如果仅有一些脚本参数进入了namedtuple,该怎么办?

以下是我想到的解决方案:

nt_param=nt(**{f:getattr(args,f,None) for f in nt._fields})

有没有更Pythonic的方法?


2
如果程序的所有参数都在nt中,我本可以将namespace=nt()传递给parser.parse_args()。但是你不能这样做,因为namedtuple是不可变的。 - anthony sottile
@AnthonySottile:谢谢,已删除。 - sds
一个小的改进是在调用getattr时删除None。由于Namespace对象已经将任何未定义的命令行参数设置为None,因此您不必显式地返回None - Christian Dean
这篇文章讨论了如何将一个可变的命名空间对象转换为不可变的。除了复制到namedtuple之外,我建议使用自定义的Namespace类。我还在https://dev59.com/wlgQ5IYBdhLWcg3wvGi4中讨论了`namedtuple`。 - hpaulj
https://pypi.python.org/pypi/recordtype 是 namedtype 的可变替代品。 - hpaulj
因此,问题归结为使用部分重叠键从字典创建namedtuple。您不仅必须选择匹配的键,还必须为缺失的键定义默认值。您可以使用parser.set_defaults来处理缺失的键问题。 - hpaulj
1个回答

0

如果您不关心namedtuple的实际类型,可以创建一个表示您的Namespace的“匿名”namedtuple。

这是我以前使用过的一种方法:

def auto_namedtuple(classname='auto_namedtuple', **kwargs):
    return collections.namedtuple(classname, tuple(kwargs))(**kwargs)

在您的情况下使用:

nt = auto_namedtuple(**vars(args))

namedtuple 中仅包含特定字段非常重要。 - sds
你所做的似乎很好,你有具体的问题吗? - anthony sottile
不是的,我只是想看看自己是否做了什么愚蠢的事情。谢谢你的帮助! - sds
请注意,虽然 _fields 有一个前导下划线,但它实际上不是“私有”属性,标准库这样做是为了避免与用户命名空间发生冲突。 (参见 https://docs.python.org/3/library/collections.html#namedtuple-factory-function-for-tuples-with-named-fields) - anthony sottile

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接