Как мне создать пространство имен Python (значение argparse.parse_args)?

Для интерактивного тестирования моего скрипта на Python я хотел бы создать Namespace объект, похожий на тот, который будет возвращен argparse.parse_args(), Очевидный способ,

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.parse_args()
Namespace()
>>> parser.parse_args("-a")
usage: [-h]
: error: unrecognized arguments: - a

Process Python exited abnormally with code 2

может привести к выходу из Python repl (как указано выше) из-за глупой ошибки.

Итак, как проще всего создать пространство имен Python с заданным набором атрибутов?

Например, я могу создать dict на лету (dict([("a",1),("b","c")])) но я не могу использовать его как Namespace:

AttributeError: 'dict' object has no attribute 'a'

6 ответов

Решение

Вы можете создать простой класс:

class Namespace:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

и это будет работать точно так же, как argparseNamespace Класс, когда дело доходит до атрибутов:

>>> args = Namespace(a=1, b='c')
>>> args.a
1
>>> args.b
'c'

Или просто импортируйте класс; это доступно из argparse модуль:

from argparse import Namespace

args = Namespace(a=1, b='c')

Начиная с Python 3.3, есть также types.SimpleNamespace, который по сути делает то же самое:

>>> from types import SimpleNamespace
>>> args = SimpleNamespace(a=1, b='c')
>>> args.a
1
>>> args.b
'c'

Два типа различны; SimpleNamespace в основном используется для sys.implementation атрибут и возвращаемое значение time.get_clock_info(),

Дальнейшие сравнения:

  • Оба класса поддерживают проверку на равенство; для двух экземпляров одного и того же класса, instance_a == instance_b Значение true, если они имеют одинаковые атрибуты с одинаковыми значениями.
  • У обоих классов есть полезный __repr__ чтобы показать, какие атрибуты у них есть.
  • Namespace() тестирование содержания объектов; 'attrname' in instance Значение true, если экземпляр пространства имен имеет атрибут namend attrname, SimpleNamespace не.
  • Namespace() объекты имеют недокументированные ._get_kwargs() метод, который возвращает отсортированный список (name, value) атрибуты для этого экземпляра. Вы можете получить то же самое для любого класса, используя sorted(vars(instance).items()),
  • В то время как SimpleNamespace() реализовано в C и Namespace() реализован в Python, доступ к атрибутам не быстрее, потому что оба используют один и тот же __dict__ хранилище для атрибутов. Тестирование на равенство и создание представления немного быстрее для SimpleNamespace() экземпляров.

Теперь рекомендуется использовать SimpleNamespace из модуля типов. Он делает то же самое, что и принятый ответ, за исключением того, что он будет быстрее и будет иметь еще несколько встроенных функций, таких как equals и repr.

from types import SimpleNamespace

sn = SimpleNamespace()
sn.a = 'test'
sn.a

# output
'test'

Сначала создайте словарь, а затем используйте его для создания пространства имен:

      from argparse import Namespace
x = {'a': 1, 'b': 2}
ns = Namespace(**x)
print(ns.a) #output 1

Изменить: как сказал @sds, эта функция в настоящее время не работает в cpython.

Альтернативным решением вашей проблемы без создания экземпляра пространства имен может бытьexit_on_errorпараметр конструктора ArgumentParser.

Если установлено значение false, он не должен выходить из вашего REPL.

Источник: https://docs.python.org/3/library/argparse.html#argumentparser-objects .

Если вы предпочитаете короткий код, вам нужно добавить всего одну дополнительную строку для определения пустого класса:

      class dummy:pass
obj = dummy()

гдеdummyможет быть любой строкой, не определенной в вашей программе. Затемobjбудет пространством имен.

Вы также можете инициализировать некоторые члены пространства имен в одной строке:

      class dummy:a=1;b=2
obj = dummy()

print(obj.a+' '+obj.b)

Недостатком дизайна Python является то, что не существует прямого способа создания самого простого объекта Python (т. е. объекта пространства имен), точно так же, как создание кортежа, списка, словаря и т. д. Если я дизайнер, я позволюa=<>создать пустое пространство именa.

Документация argparse показывает различные примеры того, что вы пытаетесь сделать:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-a")
parser.parse_args(['-a 12'])
>>> Namespace(a=' 12')
Другие вопросы по тегам