将Python argparse.Namespace()视为字典的正确方法是什么?


228

如果我想将的结果(argparse.ArgumentParser()Namespace对象)与需要字典或类映射对象的方法一起使用(请参阅collections.Mapping),那么正确的方法是什么?

C:\>python
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> args.baz = 'yippee'
>>> args['baz']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Namespace' object has no attribute '__getitem__'
>>> dir(args)
['__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__eq__', '_
_format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__
', '__str__', '__subclasshook__', '__weakref__', '_get_args', '_get_kwargs', 'ba
r', 'baz', 'foo']

“进入”对象并使用其__dict__属性是否合适?

我认为答案是否定的:__dict__闻起来像实现的约定,而不是接口的含义__getattribute____setattr__或者说__contains__是。

Answers:


384

您可以使用vars()访问名称空间的字典:

>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> d = vars(args)
>>> d
{'foo': 1, 'bar': [1, 2, 3]}

您可以根据需要直接修改字典:

>>> d['baz'] = 'store me'
>>> args.baz
'store me'

是的,可以访问__dict__属性。这是定义明确,经过测试且有保证的行为。


1
文档说:“不应修改返回的字典:未定义相应符号表上的效果。” 哪个可能仅表示vars()(是locals()globals())的行为,但我不确定。

2
嗯,我想我不太了解使用vars()__dict__
Jason S

21
@delnan有人对文档进行了错误的编辑,并进行了广泛的警告。该文档随后得到纠正。请参阅 docs.python.org/2.7/library/functions.html#vars 尽管有些特殊情况下具有只读词典(例如本地语言和类字典代理),但其他情况是可更新的。该瓦尔(OBJ)调用代名词的obj .__ dict__。对于argparse命名空间,vars(args)可以直接访问可更新的字典。
Raymond Hettinger

1
@RaymondHettinger好吧,整洁。我从/3/文档版本中得到了该注释(仔细检查后,包括3.1到3.4),因此显然在那里缺少更正。

8
@delnan我刚刚更新了3.3和3.3文档。明天将可见。感谢您指出。
Raymond Hettinger 2013年

64

从马口直行

如果您更喜欢具有类似dict的属性视图,则可以使用标准的Python习惯用法vars()

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> args = parser.parse_args(['--foo', 'BAR'])
>>> vars(args)
{'foo': 'BAR'}

— Python标准库,16.4.4.6。命名空间对象


1
仍然'foo'错过了'-'。有什么想法吗?
user2678074 '17

1
@ user2678074,这是为了匹配shell标志。破折号在python执行中是多余的。
Erich

vars(args)给我TypeError: 'dict' object is not callable
user5359531

6
@ user5359531您可能vars用变量覆盖了全局变量。您可以用来__builtins__.vars直接访问它,也del vars可以停止对其进行阴影处理。
尼克T

@NickT较小的更正:Python函数是静态作用域的,因此,如果在函数中隐藏全局变量,则该标识符将始终引用该函数中的局部变量,即使在赋值之前或之后也是如此del。在模块作用域内,del 可以 “隐藏”内置函数。
augurar

-1

“进入”对象并使用其dict属性是否合适?

通常,我会说“不”。但是Namespace,令我震惊的是过度设计,可能是因为类无法从内置类型继承。

另一方面,Namespace确实提供了一种针对argparse的面向任务的方法,我想不出需要抓住的情况__dict__,但是我的想象力的极限与您的一样。


11
访问__dict__属性是完全可以的。内省是语言的基础。该属性被公开是有原因的:-)
Raymond Hettinger 2013年

8
但是Python中的所有内容都是“公开的”。实例中使用的实现变量和它提供的公共接口之间没有区别(除了最主要的下划线约定以外)。尤其是在类字典的对象中:实例方法与作为函数的字典值之间的界限有点​​模糊。
詹森·S

如果将参数作为命名参数传递?do_something(**args.__dict__)
OrangeDog '18 -10-26
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.