qual é a maneira correta de tratar Python argparse.Namespace () como um dicionário?

228

Se eu quiser usar os resultados de argparse.ArgumentParser(), que é um Namespaceobjeto, com um método que espera um dicionário ou um objeto parecido com o mapeamento (consulte collections.Mapping ), qual é a maneira correta de fazer isso?

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

É apropriado "alcançar" um objeto e usar sua __dict__propriedade?

Eu acho que a resposta é não: __dict__cheira como uma convenção para a implementação, mas não para uma interface, a maneira __getattribute__ou __setattr__ou __contains__parecem ser.

Jason S
fonte

Respostas:

385

Você pode acessar o dicionário do espaço para nome com vars () :

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

Você pode modificar o dicionário diretamente se desejar:

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

Sim, não há problema em acessar o atributo __dict__. É um comportamento bem definido, testado e garantido.

Raymond Hettinger
fonte
1
Os documentos dizem: "O dicionário retornado não deve ser modificado: os efeitos na tabela de símbolos correspondentes são indefinidos". O que pode se referir apenas ao comportamento de vars()(que é um locals()ou globals()), mas não tenho muita certeza.
2
hmm, acho que realmente não entendo a diferença entre usar vars()e__dict__
Jason S
21
@delnan Alguém fez uma edição incorreta nos documentos e fez uma advertência geral. Os documentos foram posteriormente corrigidos. Consulte docs.python.org/2.7/library/functions.html#vars Embora existam alguns casos especiais que possuem dicionários somente leitura (como locais e proxies de dicionário de classes), o restante dos casos é atualizável. A chamada vars (obj) é sinônimo de obj .__ dict__. No caso de um namespace argparse , vars (args) fornece acesso direto a um dicionário atualizável.
Raymond Hettinger
1
@RaymondHettinger Okay, puro. Recebi essa nota da /3/versão dos documentos (em uma inspeção mais detalhada, incluindo 3.1 a 3.4), então a correção está aparentemente ausente.
8
Acabei de atualizar os documentos 3.3 e 3.3. Será visível amanhã. Obrigado por apontar isso.
Raymond Hettinger
64

Diretamente da boca do cavalo :

Se você preferir ter uma visão semelhante aos ditados, poderá usar o idioma padrão do Python vars():

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

- Biblioteca Padrão do Python, 16.4.4.6. O objeto Namespace

Eugene Yarmash
fonte
1
Ainda 'foo' erra '-'. Alguma ideia disso?
precisa saber é o seguinte
1
@ user2678074, este é intencional para corresponder aos sinalizadores de shell. Os traços são estranhos na execução do python.
Erich
vars(args)me dáTypeError: 'dict' object is not callable
user5359531
6
@ user5359531 você provavelmente substituiu o global varspor uma variável. Você pode usar __builtins__.varspara acessá-lo diretamente ou del varsparar de sombrear.
Nick T
@NickT Correção menor: as funções Python têm escopo estatístico; portanto, se você sombrear uma variável global em uma função, esse identificador sempre se referirá à variável local dentro dessa função, mesmo antes de ser atribuída ou depois del. No âmbito do módulo del irá trabalhar para builtins "un-sombra".
Aug
-1

É apropriado "alcançar" um objeto e usar sua propriedade dict ?

Em geral, eu diria "não". No entanto Namespace, me pareceu um excesso de engenharia, possivelmente a partir de quando as classes não puderam herdar dos tipos internos.

Por outro lado, Namespaceapresenta uma abordagem orientada a tarefas para o argparse, e não consigo pensar em uma situação que exigiria agarrá-lo __dict__, mas os limites da minha imaginação não são os mesmos que os seus.

msw
fonte
11
Não há problema em acessar o atributo __dict__. A introspecção é fundamental para a linguagem. O atributo foi tornado público por uma razão :-)
Raymond Hettinger
8
Mas tudo em Python é "público". Não há distinções (exceto a convenção de sublinhado principal) entre as variáveis ​​de implementação usadas em uma instância e a interface pública que ela apresenta. Especialmente em um objeto semelhante a dicionário: a linha entre métodos de instância e valores de dicionário que são funções é um pouco embaçada.
Jason S
Se você está passando os argumentos como parâmetros nomeados? do_something(**args.__dict__)
OrangeDog 26/10