Как правильно трактовать Python argparse.Namespace () как словарь?

228

Если я хочу использовать результаты argparse.ArgumentParser(), являющиеся Namespaceобъектом, с методом, который ожидает словарь или объект, подобный отображению (см. Collection.Mapping ), каков правильный способ сделать это?

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

Уместно ли "проникать" в объект и использовать его __dict__свойство?

Я думаю , ответ нет: __dict__пахнет конвенции для реализации, но не для интерфейса, пути __getattribute__или __setattr__или __contains__кажусь.

Джейсон С
источник

Ответы:

385

Вы можете получить доступ к словарю пространства имен с помощью vars () :

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

Вы можете изменить словарь напрямую, если хотите:

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

Да, это нормально, чтобы получить доступ к атрибуту __dict__. Это четко определенное, проверенное и гарантированное поведение.

Раймонд Хеттингер
источник
1
В документах сказано: «Возвращаемый словарь не должен изменяться: эффекты на соответствующей таблице символов не определены». Который может относиться только к поведению vars()(которое либо либо, locals()либо globals()), но я не совсем уверен.
2
хм, наверное, я не совсем понимаю разницу между использованием vars()и__dict__
Джейсон С
21
@delnan Кто-то неверно отредактировал документы и сделал слишком широкое предупреждение. Документы были впоследствии исправлены. См. Docs.python.org/2.7/library/functions.html#vars. Хотя в некоторых особых случаях имеются словари, доступные только для чтения (например, локальные и прокси-словарь классов), остальные случаи можно обновлять. Вары (объект) вызов является синонимом OBJ .__ dict__. В случае argparse имен, вары (арг) дает прямой доступ к обновляемому словарю.
Раймонд Хеттингер
1
@RaymondHettinger Хорошо, аккуратно. Я получил это примечание из /3/версии документов (при ближайшем рассмотрении, включая 3.1 до 3.4), так что исправление там явно отсутствует.
8
@delnan Я только что обновил 3.3 и 3.3 документы. Это будет видно завтра. Спасибо за указание на это.
Рэймонд Хеттингер
64

Прямо изо рта лошади :

Если вы предпочитаете использовать атрибуты в стиле dict, вы можете использовать стандартную идиому Python vars():

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

- Стандартная библиотека Python, 16.4.4.6. Объект пространства имен

Евгений Ярмаш
источник
1
Тем не менее 'Foo' пропускает '-'. Есть идеи?
user2678074
1
@ user2678074 это преднамеренное совпадение с флагами оболочки. Черты посторонние внутри исполнения Python.
Эрих
vars(args)дает мнеTypeError: 'dict' object is not callable
user5359531
6
@ user5359531 вы, вероятно, перезаписали глобальные varsпеременные. Вы можете использовать, __builtins__.varsчтобы получить к нему доступ напрямую, или del varsчтобы остановить его.
Ник Т
@NickT Незначительное исправление: функции Python имеют статическую область видимости, поэтому, если вы скрываете глобальную переменную в функции, этот идентификатор всегда будет ссылаться на локальную переменную внутри этой функции, даже до того, как она будет назначена или после del. В области видимости модуля del будут работать «не-теневые» встроенные функции.
augurar
-1

Правильно ли "достать" объект и использовать его свойство dict ?

В общем, я бы сказал «нет». Однако Namespaceэто показалось мне слишком сложным, возможно, с тех пор, когда классы не могли наследовать от встроенных типов.

С другой стороны, Namespaceпредставляет собой ориентированный на задачи подход к argparse, и я не могу представить себе ситуацию, которая потребовала бы захвата __dict__, но границы моего воображения не совпадают с вашими.

MSW
источник
11
Это совершенно нормально, чтобы получить доступ к атрибуту __dict__. Самоанализ имеет фундаментальное значение для языка. Атрибут был обнародован по причине :-)
Раймонд Хеттингер
8
Но все в Python "публично". Нет никаких различий (за исключением соглашения о нижнем подчеркивании) между переменными реализации, используемыми в экземпляре, и открытым интерфейсом, который он представляет. Особенно в объекте, подобном словарю: граница между методами экземпляра и значениями словаря, которые являются функциями, немного размыта.
Джейсон С
Если вы передаете аргументы как именованные параметры? do_something(**args.__dict__)
OrangeDog