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__はないようです。

回答:


385

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__
ジェイソンS

21
@delnan誰かがドキュメントに対して誤った編集を行い、広範囲にわたる警告を行いました。その後、ドキュメントが修正されました。docs.python.org/2.7/library/functions.html#vars を参照してください。 読み取り専用の辞書(ローカルやクラスディクショナリプロキシなど)がある特別なケースもありますが、残りのケースは更新可能です。VARS(OBJ)の呼び出しは、OBJ .__ dict__にと同義です。argparse名前空間の場合、vars(args)は更新可能な辞書への直接アクセスを提供します。
レイモンドヘッティンガー2013年

1
@RaymondHettingerわかりました。私は/3/ドキュメントのバージョン(詳細な検査では、3.1から3.4を含む)からそのメモを得たので、そこには修正が欠けているようです。

8
@delnan 3.3と3.3のドキュメントを更新しました。明日見えます。指摘してくれてありがとう。
レイモンドヘッティンガー

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。Namespaceオブジェクト


1
それでも「foo」は「-」を逃します。何か考えはありますか?
user2678074 2017

1
@ user2678074これは、シェルフラグと一致させるための意図的なものです。ダッシュはPythonの実行内では無関係です。
エーリヒ

vars(args)くれますTypeError: 'dict' object is not callable
user5359531

6
@ user5359531おそらくvars変数でグローバルを上書きしました。を使用__builtins__.varsして直接アクセスしたりdel vars、シャドウイングを停止したりできます。
Nick T

@NickTマイナー修正:Python関数のスコープは静的であるため、関数内のグローバル変数をシャドウすると、その識別子は、関数が割り当てられる前でも後でも、常にその関数内のローカル変数を参照しますdel。モジュールのスコープでdel 、ビルトインを「非シャドウ」に機能させます。
augurar

-1

オブジェクトに「到達」し、そのdictプロパティを使用することは適切ですか?

一般的には「いいえ」と言います。しかしNamespace、おそらくクラスが組み込み型から継承できなかったときから、過度に設計されたと私は思いました。

一方、Namespaceはargparseへのタスク指向のアプローチを示しています。私はを取得する必要がある状況を考えることはできません__dict__が、私の想像力の限界はあなたのものと同じではありません。


11
__dict__属性にアクセスしても問題ありません。イントロスペクションは言語の基本です。この属性は次の理由により公開されました:-)
Raymond Hettinger

8
しかし、Pythonのすべては「公開」されています。インスタンスで使用される実装変数と、それが提供するパブリックインターフェイスとの間には(先頭のアンダースコア規則を除いて)違いはありません。特にディクショナリのようなオブジェクトでは、インスタンスメソッドと関数であるディクショナリ値の間の線が少しぼやけています。
Jason S

引数を名前付きパラメーターとして渡す場合は?do_something(**args.__dict__)
OrangeDog 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.