Was ist der richtige Weg, um Python argparse.Namespace () als Wörterbuch zu behandeln?

227

Wenn ich die Ergebnisse argparse.ArgumentParser()eines NamespaceObjekts mit einer Methode verwenden möchte , die ein Wörterbuch oder ein Mapping-ähnliches Objekt erwartet (siehe Sammlungen.Mapping ), wie gehe ich dann richtig vor?

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

Ist es richtig, in ein Objekt zu "greifen" und seine __dict__Eigenschaft zu nutzen?

Ich würde denken, die Antwort ist nein: __dict__riecht nach einer Konvention für die Implementierung, aber nicht nach einer Schnittstelle, wie __getattribute__oder __setattr__oder wie es __contains__scheint.

Jason S.
quelle

Antworten:

381

Sie können mit vars () auf das Wörterbuch des Namespace zugreifen :

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

Sie können das Wörterbuch direkt ändern, wenn Sie möchten:

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

Ja, es ist in Ordnung, auf das Attribut __dict__ zuzugreifen. Es ist ein klar definiertes, getestetes und garantiertes Verhalten.

Raymond Hettinger
quelle
1
In den Dokumenten heißt es: "Das zurückgegebene Wörterbuch sollte nicht geändert werden. Die Auswirkungen auf die entsprechende Symboltabelle sind undefiniert." Was sich vielleicht nur auf das Verhalten von vars()(was entweder locals()oder ist globals()) bezieht , aber ich bin mir nicht wirklich sicher.
2
hmm, ich glaube ich verstehe den Unterschied zwischen vars()und__dict__
Jason S
20
@delnan Jemand hatte die Dokumente falsch bearbeitet und eine zu breite Ermahnung ausgesprochen. Die Dokumente wurden anschließend korrigiert. Siehe docs.python.org/2.7/library/functions.html#vars Während es einige Sonderfälle gibt, die schreibgeschützte Wörterbücher enthalten (z. B. Ortsansässige und Klassenwörterbuch-Proxys), können die übrigen Fälle aktualisiert werden. Der Aufruf von vars (obj) ist gleichbedeutend mit obj .__ dict__. Im Fall eines Argparse- Namespace bietet vars (args) direkten Zugriff auf ein aktualisierbares Wörterbuch.
Raymond Hettinger
1
@RaymondHettinger Okay, ordentlich. Ich habe diese Notiz aus der /3/Version der Dokumente erhalten (bei näherer Betrachtung, 3.1 bis 3.4 einschließlich), so dass die Korrektur dort anscheinend fehlt.
8
@delnan Ich habe gerade die 3.3 und 3.3 Dokumente aktualisiert. Es wird morgen sichtbar sein. Vielen Dank für den Hinweis.
Raymond Hettinger
63

Direkt aus dem Maul des Pferdes :

Wenn Sie eine diktartige Ansicht der Attribute bevorzugen, können Sie das Standard-Python-Idiom verwenden vars():

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

- Die Python-Standardbibliothek, 16.4.4.6. Das Namespace-Objekt

Eugene Yarmash
quelle
1
Immer noch 'foo' vermisst '-'. Irgendeine Idee dazu?
user2678074
1
@ user2678074 Dies ist beabsichtigt, um Shell-Flags zu entsprechen. Die Striche sind in der Python-Ausführung irrelevant.
Erich
vars(args)gibt mirTypeError: 'dict' object is not callable
user5359531
6
@ user5359531 Sie haben wahrscheinlich die globale varsmit einer Variablen überschrieben . Sie können verwenden __builtins__.vars, um direkt darauf zuzugreifen oder del varsdas Abschatten zu beenden.
Nick T
@NickT Kleinere Korrektur: Python-Funktionen haben einen statischen Gültigkeitsbereich. Wenn Sie also eine globale Variable in einer Funktion schattieren, bezieht sich dieser Bezeichner immer auf die lokale Variable innerhalb dieser Funktion, noch bevor sie zugewiesen wird oder danach del. Im Modul del wird der Bereich zum "Entschatten" von eingebauten Funktionen verwendet.
August
-1

Ist es richtig, in ein Objekt zu "greifen" und dessen diktierte Eigenschaft zu verwenden?

Im Allgemeinen würde ich "nein" sagen. Es Namespacehat mich jedoch als überentwickelt empfunden, möglicherweise aus der Zeit, als Klassen nicht von integrierten Typen erben konnten.

Auf der anderen Seite Namespacepräsentiert sich eine aufgabenorientierte Herangehensweise an Argparse, und ich kann mir keine Situation vorstellen, die es erforderlich machen würde, das zu ergreifen __dict__, aber die Grenzen meiner Vorstellungskraft sind nicht die gleichen wie Ihre.

msw
quelle
11
Es ist vollkommen in Ordnung, auf das Attribut __dict__ zuzugreifen. Selbstbeobachtung ist für die Sprache von grundlegender Bedeutung. Das Attribut wurde aus einem Grund veröffentlicht :-)
Raymond Hettinger
8
Aber alles in Python ist "öffentlich". Es gibt keine Unterschiede (mit Ausnahme der führenden Unterstrichkonvention) zwischen den in einer Instanz verwendeten Implementierungsvariablen und der darin enthaltenen öffentlichen Schnittstelle. Besonders in einem wörterbuchähnlichen Objekt: Die Grenze zwischen Instanzmethoden und Wörterbuchwerten, die Funktionen sind, ist etwas verschwommen.
Jason S
Wenn Sie die Argumente als benannte Parameter übergeben? do_something(**args.__dict__)
OrangeDog