qual è il modo giusto di trattare Python argparse.Namespace () come un dizionario?


228

Se voglio usare i risultati di argparse.ArgumentParser(), che è un Namespaceoggetto, con un metodo che prevede un dizionario o un oggetto simile a una mappatura (vedi raccolte.Mapping ), qual è il modo giusto per farlo?

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

È corretto "raggiungere" un oggetto e usare la sua __dict__proprietà?

Penserei che la risposta sia no: __dict__profuma di convenzione per l'implementazione, ma non per un'interfaccia, il modo __getattribute__o __setattr__o __contains__sembra essere.

Risposte:


385

Puoi accedere al dizionario dello spazio dei nomi 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]}

Puoi modificare direttamente il dizionario se desideri:

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

Sì, è possibile accedere all'attributo __dict__. È un comportamento ben definito, testato e garantito.


1
I documenti dicono: "Il dizionario restituito non deve essere modificato: gli effetti sulla tabella dei simboli corrispondente non sono definiti." Che può riferirsi solo al comportamento di vars()(che è o locals()o globals()), ma non ne sono davvero sicuro.

2
hmm, immagino di non capire davvero la differenza tra l'utilizzo vars()e__dict__
Jason S,

21
@delnan Qualcuno aveva apportato una modifica errata ai documenti e fatto un ammonimento troppo ampio. I documenti sono stati successivamente corretti. Vedi docs.python.org/2.7/library/functions.html#vars Mentre ci sono alcuni casi speciali che hanno dizionari di sola lettura (come i locali e i proxy dei dizionari di classe), il resto dei casi è aggiornabile. La chiamata vars (obj) è sinonimo di obj .__ dict__. Nel caso di uno spazio dei nomi argparse , vars (args) dà accesso diretto a un dizionario aggiornabile.
Raymond Hettinger,

1
@RaymondHettinger Va bene, pulito. Ho preso quella nota dalla /3/versione dei documenti (a un esame più attento, da 3.1 a 3.4 compreso), quindi apparentemente la correzione manca.

8
@delnan Ho appena aggiornato i documenti 3.3 e 3.3. Sarà visibile domani. Grazie per segnalarlo.
Raymond Hettinger,

64

Direttamente dalla bocca del cavallo :

Se preferisci avere una vista simile agli attributi, puoi usare il linguaggio standard di Python vars():

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

- La libreria standard di Python, 16.4.4.6. L'oggetto spazio dei nomi


1
Ancora 'foo' manca '-'. Qualche idea a riguardo?
user2678074

1
@ user2678074 questo è intenzionale per abbinare i flag di shell. I trattini sono estranei all'interno dell'esecuzione di Python.
Erich,

vars(args)mi dàTypeError: 'dict' object is not callable
user5359531

6
@utente5359531 probabilmente hai sovrascritto il globale varscon una variabile. Puoi usarlo __builtins__.varsper accedervi direttamente o del varsper smettere di oscurarlo.
Nick T,

@NickT Correzione minore: le funzioni di Python hanno un ambito statico, quindi se si ombreggia una variabile globale in una funzione, quell'identificatore si riferirà sempre alla variabile locale all'interno di quella funzione, anche prima che sia assegnata o dopo del. Al campo di applicazione del modulo del si lavorerà per builtins "non-ombra".
agosto

-1

È corretto "raggiungere" un oggetto e usare la sua proprietà dict ?

In generale, direi "no". Tuttavia, Namespacemi è sembrato troppo ingegnerizzato, probabilmente da quando le classi non potevano ereditare dai tipi predefiniti.

D'altra parte, Namespacepresenta un approccio orientato al compito di argparse, e non riesco a pensare a una situazione che richiederebbe di afferrare __dict__, ma i limiti della mia immaginazione non sono gli stessi della tua.


11
È perfettamente corretto accedere all'attributo __dict__. L'introspezione è fondamentale per la lingua. L'attributo è stato reso pubblico per un motivo :-)
Raymond Hettinger,

8
Ma tutto in Python è "pubblico". Non ci sono distinzioni (tranne la convenzione di sottolineatura iniziale) tra le variabili di implementazione utilizzate in un'istanza e l'interfaccia pubblica che presenta. Soprattutto in un oggetto simile a un dizionario: la linea tra i metodi di istanza e i valori di dizionario che sono funzioni è un po 'sfocata.
Jason S,

Se stai passando gli argomenti come parametri nominati? do_something(**args.__dict__)
OrangeDog,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.