apa cara yang tepat untuk memperlakukan Python argparse.Namespace () sebagai kamus?

228

Jika saya ingin menggunakan hasil argparse.ArgumentParser(), yang merupakan Namespaceobjek, dengan metode yang mengharapkan kamus atau objek seperti pemetaan (lihat collections.Mapping ), apa cara yang tepat untuk melakukannya?

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']

Apakah pantas untuk "menjangkau" suatu objek dan menggunakan __dict__propertinya?

Saya akan berpikir jawabannya adalah: __dict__baunya seperti konvensi untuk implementasi, tetapi tidak untuk antarmuka, cara __getattribute__atau __setattr__atau __contains__tampaknya.

Jason S
sumber

Jawaban:

385

Anda dapat mengakses kamus namespace dengan vars () :

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

Anda dapat memodifikasi kamus secara langsung jika ingin:

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

Ya, tidak apa-apa untuk mengakses atribut __dict__. Ini adalah perilaku yang jelas, teruji, dan dijamin.

Raymond Hettinger
sumber
1
Dokumen mengatakan: "Kamus yang dikembalikan tidak boleh dimodifikasi: efek pada tabel simbol yang sesuai tidak ditentukan." Yang mungkin hanya merujuk pada perilaku vars()(yang merupakan salah satu locals()atau globals()), tapi saya tidak begitu yakin.
2
hmm, saya kira saya tidak begitu mengerti perbedaan antara menggunakan vars()dan__dict__
Jason S
21
@delnan Seseorang membuat kesalahan edit pada dokumen dan membuat peringatan yang terlalu luas. Dokumen kemudian dikoreksi. Lihat docs.python.org/2.7/library/functions.html#vars Meskipun ada beberapa kasus khusus yang memiliki kamus read-only (seperti penduduk lokal dan proksi kamus kelas), sisa kasing dapat diperbarui. The vars (obj) panggilan ini identik dengan obj .__ dict__. Dalam kasus namespace argparse , vars (args) memberikan akses langsung ke kamus yang dapat diperbarui.
Raymond Hettinger
1
@RaymondHettinger Oke, rapi. Saya mendapat catatan itu dari /3/versi dokumen (pada pemeriksaan lebih dekat, termasuk 3.1 ke 3.4), sehingga koreksi tampaknya hilang di sana.
8
@delnan Saya baru saja memperbarui dokumen 3.3 dan 3.3. Itu akan terlihat besok. Terima kasih telah menunjukkannya.
Raymond Hettinger
64

Langsung dari mulut kuda :

Jika Anda lebih suka memiliki atribut seperti dict, Anda dapat menggunakan idiom Python standar, vars() :

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

- Perpustakaan Standar Python, 16.4.4.6. Objek Namespace

Eugene Yarmash
sumber
1
Masih 'foo' rindu '-'. Ada ide untuk itu?
user2678074
1
@ user2678074 ini disengaja untuk mencocokkan flag shell. Garis putus-putus dalam eksekusi python.
Erich
vars(args)memberi sayaTypeError: 'dict' object is not callable
user5359531
6
@ user5359531 Anda mungkin menimpa global varsdengan variabel. Anda dapat menggunakannya __builtins__.varsuntuk mengaksesnya secara langsung, atau del varsuntuk berhenti membayangi.
Nick T
@NickT Koreksi kecil: Fungsi-fungsi Python dicakup secara statis, jadi jika Anda membayangi variabel global dalam suatu fungsi, pengenal itu akan selalu merujuk ke variabel lokal di dalam fungsi itu, bahkan sebelum ditetapkan atau sesudahnya del. Pada lingkup modul del akan bekerja untuk "un-shadow" builtin.
augurar
-1

Apakah pantas untuk "menjangkau" suatu objek dan menggunakan properti diktnya ?

Secara umum, saya akan mengatakan "tidak". NamunNamespace saya sudah terlalu direkayasa, mungkin sejak kelas tidak bisa mewarisi dari tipe bawaan.

Di sisi lain, Namespacememang menyajikan pendekatan berorientasi tugas untuk argparse, dan saya tidak bisa memikirkan situasi yang akan membutuhkan untuk meraih __dict__, tetapi batas imajinasi saya tidak sama dengan Anda.

msw
sumber
11
Sangat oke untuk mengakses atribut __dict__. Introspeksi adalah hal mendasar dalam bahasa. Atribut itu dipublikasikan karena suatu alasan :-)
Raymond Hettinger
8
Tapi semua yang ada di Python adalah "publik". Tidak ada perbedaan (kecuali konvensi garis bawah terkemuka) antara variabel implementasi yang digunakan dalam contoh, dan antarmuka publik yang disajikannya. Terutama dalam objek seperti kamus: garis antara metode instance, dan nilai kamus yang berfungsi, agak kabur.
Jason S
Jika Anda melewatkan argumen sebagai parameter bernama? do_something(**args.__dict__)
OrangeDog