Как мне создать пространство имен 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)
и это будет работать точно так же, как argparse
Namespace
Класс, когда дело доходит до атрибутов:
>>> 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, если экземпляр пространства имен имеет атрибут namendattrname
,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')