¿Cuál es la forma correcta de tratar Python argparse.Namespace () como un diccionario?

228

Si quiero usar los resultados de argparse.ArgumentParser(), que es un Namespaceobjeto, con un método que espera un diccionario o un objeto similar al mapeo (ver colecciones.Mapa ), ¿cuál es la forma correcta de hacerlo?

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

¿Es apropiado "alcanzar" un objeto y usar su __dict__propiedad?

Yo creo que la respuesta es no: __dict__huele a una convención para la implementación, pero no para una interfaz, la forma __getattribute__o el __setattr__o __contains__parecen ser.

Jason S
fuente

Respuestas:

385

Puede acceder al diccionario del espacio de nombres con vars () :

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

Puede modificar el diccionario directamente si lo desea:

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

Sí, está bien acceder al atributo __dict__. Es un comportamiento bien definido, probado y garantizado.

Raymond Hettinger
fuente
1
Los documentos dicen: "El diccionario devuelto no debe modificarse: los efectos en la tabla de símbolos correspondiente no están definidos". Lo cual solo puede referirse al comportamiento de vars()(que es locals()o globals()) o , pero no estoy realmente seguro.
2
hmm, supongo que realmente no entiendo la diferencia entre usar vars()y__dict__
Jason S
21
@delnan Alguien había hecho una edición incorrecta de los documentos e hizo una advertencia general. Los documentos fueron corregidos posteriormente. Consulte docs.python.org/2.7/library/functions.html#vars Si bien hay algunos casos especiales que tienen diccionarios de solo lectura (como los locales y los servidores proxy de clase), el resto de los casos son actualizables. La llamada vars (obj) es sinónimo de obj .__ dict__. En el caso de un espacio de nombres argparse , vars (args) da acceso directo a un diccionario actualizable.
Raymond Hettinger
1
@RaymondHettinger Bien, ordenado. Recibí esa nota de la /3/versión de los documentos (en una inspección más cercana, 3.1 a 3.4 incluidos), por lo que aparentemente la corrección falta allí.
8
@delnan Acabo de actualizar los documentos 3.3 y 3.3. Será visible mañana. Gracias por mencionarlo.
Raymond Hettinger
64

Directamente de la boca del caballo :

Si prefiere tener una vista tipo dict de los atributos, puede usar el idioma estándar de Python vars():

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

- La biblioteca estándar de Python, 16.4.4.6. El objeto de espacio de nombres

Eugene Yarmash
fuente
1
Todavía 'foo' echa de menos '-'. ¿Alguna idea de eso?
user2678074
1
@ user2678074 esto es intencional para hacer coincidir los indicadores de shell. Los guiones son extraños dentro de la ejecución de Python.
Erich
vars(args)me daTypeError: 'dict' object is not callable
user5359531
66
@ user5359531 probablemente sobrescribió el global varscon una variable. Puede usarlo __builtins__.varspara acceder directamente o del varspara dejar de seguirlo.
Nick T
@NickT Corrección menor: las funciones de Python tienen un alcance estático, por lo que si sombrea una variable global en una función, ese identificador siempre se referirá a la variable local dentro de esa función, incluso antes de que se asigne o después del. En el alcance del módulo del , funcionará para "quitar la sombra" de las construcciones.
augurar
-1

¿Es apropiado "alcanzar" un objeto y usar su propiedad dict ?

En general, diría "no". Sin embargo, Namespaceme ha parecido una ingeniería excesiva, posiblemente de cuando las clases no podían heredar de los tipos incorporados.

Por otro lado, Namespacepresenta un enfoque orientado a tareas para argparse, y no puedo pensar en una situación que requiera agarrar __dict__, pero los límites de mi imaginación no son los mismos que los suyos.

msw
fuente
11
Está perfectamente bien acceder al atributo __dict__. La introspección es fundamental para el lenguaje. El atributo se hizo público por una razón :-)
Raymond Hettinger
8
Pero todo en Python es "público". No hay distinciones (excepto la convención de subrayado principal) entre las variables de implementación utilizadas en una instancia y la interfaz pública que presenta. Especialmente en un objeto tipo diccionario: la línea entre los métodos de instancia y los valores del diccionario que son funciones es un poco borrosa.
Jason S
Si pasa los argumentos como parámetros con nombre? do_something(**args.__dict__)
OrangeDog