请解释argparse模块中代码片段背后的推理

时间:2013-01-15 13:33:26

标签: python argparse

我正在查看内置argparse._AppendAction的源代码,该代码实现"append"操作,并对way it is implemented感到困惑:

    def __call__(self, parser, namespace, values, option_string=None):
        items = _copy.copy(_ensure_value(namespace, self.dest, []))
        items.append(values)
        setattr(namespace, self.dest, items)

要打破它:

  • _ensure_value与属性dict.setdefault类似。也就是说,如果namespace具有名称为self.dest的属性,则会返回该属性,否则会将其设置为[]并返回。
  • _copy.copy(x)只返回一个浅表副本。当x是列表时,它与list(x)完全相同(但速度较慢)。
  • 然后该项目将附加到从namespace获取的列表的副本
  • 最后,self.dest的{​​{1}}属性被副本覆盖,这会导致旧列表被垃圾收集。

为什么会以这样一种迂回而低效的方式,为每个附加物扔掉一个完整的清单?为什么这不够?

namespace

1 个答案:

答案 0 :(得分:6)

我不是实施方面的专家,所以(免责声明)这只是一个猜测。通过此实现,用户可以在default=...的调用中将列表作为add_argument传递,而不会在argparse中进行变更。也许这种安全性是开发人员出于某种原因所希望的。

你提到的效率低下并不是什么大问题。它用于解析命令行参数,因此在大量使用时,此函数可能仅被调用每个程序10次。


我已经测试了这个,事实上,如果我使用以下脚本(其中argparse_temp只是argparse.py被复制到当前目录,所以我可以使用它):

import argparse_temp as argparse

lst = [1,2,3]
parser = argparse.ArgumentParser()
parser.add_argument('-l',default=lst,action='append')
print parser.parse_args()
print lst

打印(当被称为:python test1.py -l 4时):

Namespace(l=[1, 2, 3, '4'])
[1, 2, 3]

argparse为原样,但是:

Namespace(l=[1, 2, 3, '4'])
[1, 2, 3, '4']

提出您的建议。

如果您打印add_argument返回的操作,则会获得:

_AppendAction(option_strings=['-l'], dest='l', nargs=None, const=None, default=[1, 2, 3, '4'], type=None, choices=None, help=None, metavar=None)

可以想象,argparse依赖于实现中其他位置的操作。 (请注意,此处default也已发生变异。)