Python argparse: как ссылаться на параметр с da sh в нем - PullRequest
0 голосов
/ 05 августа 2020

Я использую argparse , и я хотел бы указать позиционный аргумент с da sh в нем. argparse, кажется, позволяет мне это сделать. Действительно, он отображается в пространстве имен parse_args (), но я не могу понять, как ссылаться на соответствующее значение. Вот минимальный пример (обратите внимание на da sh в 'a-string'):

#!/usr/bin/env python3

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('a-string', help='A string')

args = parser.parse_args()

# AttributeError: 'Namespace' object has no attribute 'a_string'
#print("Argument was: " + args.a_string)

# TypeError: 'Namespace' object is not subscriptable
#print("Argument was: " + args['a-string'])

# AttributeError: 'Namespace' object has no attribute 'a'
#print("Argument was: " + args.a-string)

# I give up. Ask StackOverflow.

Сначала я думал решить эту проблему с помощью аргумента dest к add_argument , но я получаю «ValueError: dest передан дважды для позиционного аргумента», если я добавляю dest к позиционному аргументу. Как мне сослаться на значение этого позиционного аргумента?

Ответы [ 2 ]

2 голосов
/ 05 августа 2020

Аргументы даны как атрибуты объекта пространства имен, возвращаемого parse_args(). Но идентификаторы (включая атрибуты) не могут содержать дефис (по крайней мере, если вы хотите получить к ним прямой доступ), потому что это знак минус, а это означает что-то еще.

Если вам нужен ваш аргумент чтобы его можно было назвать «строкой» для пользователя, но доступным в вашем коде как a_string (что было одним из ваших попыток), вы можете использовать аргумент metavar, чтобы указать, как он описывается для пользователя.

parser.add_argument('a_string', help='A string', metavar='a-string')

args = parser.parse_args()
print(args.a_string)

Аргумент появится в информации об использовании как:

positional arguments:
  a-string    A string

https://docs.python.org/3/library/argparse.html#argparse .ArgumentParser.add_argument

0 голосов
/ 05 августа 2020

dest с '-' обрабатывается по-разному с необязательным и позиционным.

In [298]: import argparse                                                                            
In [299]: parser = argparse.ArgumentParser()                                                         
In [300]: a1 = parser.add_argument('--a-string');                                                 
In [301]: a2 = parser.add_argument('foo-string');                                                    
In [302]: parser.print_help()                                                                        
usage: ipython3 [-h] [--a-string A_STRING] foo-string

positional arguments:
  foo-string

optional arguments:
  -h, --help           show this help message and exit
  --a-string A_STRING

dest для optional получается из первого 'длинного' флага, заменяя любой внутренний '-' с '_'. dest для позиционного значения является первым аргументом без каких-либо замен. У вас есть полный контроль над позиционным dest.

In [304]: args = parser.parse_args(['xxx'])                                                          
In [305]: args                                                                                       
Out[305]: Namespace(a_string=None, **{'foo-string': 'xxx'})
In [306]: args.a_string                                                                              

Доступ к da sh dest все еще возможен:

In [307]: vars(args)['foo-string']                                                                   
Out[307]: 'xxx'
In [308]: getattr(args, 'foo-string')                                                                
Out[308]: 'xxx'

Замена '- / _' выполнена поэтому вы можете использовать '-' во флаге (обычная практика POSIX), но по-прежнему обращаться к атрибуту с синтаксисом точки.

Внутренне argparse использует getattr и setattr, поэтому он не ограничить dest. Это не обязательно должно быть действительное имя python. Это верно как для опциональных, так и для позиционных.

Если я дал необязательное значение dest (отличное от флага),

In [310]: a1.dest = 'a-string'     # changing the existing argument
                                                              
In [312]: parser.print_help()                                                                        
usage: ipython3 [-h] [--a-string A-STRING] foo-string

positional arguments:
  foo-string

optional arguments:
  -h, --help           show this help message and exit
  --a-string A-STRING

Это изменило 'A_STRING' на ' A-STRING ', но также изменили имя атрибута:

In [313]: args = parser.parse_args(['xxx'])                                                          
In [314]: args                                                                                       
Out[314]: Namespace(**{'a-string': None, 'foo-string': 'xxx'})

metavar позволяет нам контролировать, как значение отображается в справке. Затем мы можем выбрать dest как что-нибудь практичное (или непрактичное, если мы предпочитаем).

In [315]: a1.dest='a_string'; a1.metavar='MY-STRING'                                                 
In [316]: a2.dest='foo_bar'; a2.metavar='YOUR-STRING'                                                
In [317]: parser.print_help()                                                                        
usage: ipython3 [-h] [--a-string MY-STRING] YOUR-STRING

positional arguments:
  YOUR-STRING

optional arguments:
  -h, --help            show this help message and exit
  --a-string MY-STRING
In [318]: args = parser.parse_args(['xxx'])                                                          
In [319]: args                                                                                       
Out[319]: Namespace(a_string=None, foo_bar='xxx')

Уродливое назначение, независимо от флагов и метавара:

In [320]: a1.dest='a-#$'; a2.dest='-xxx$3'                                                           
In [321]: args = parser.parse_args(['xxx'])                                                          
In [322]: args                                                                                       
Out[322]: Namespace(**{'-xxx$3': 'xxx', 'a-#$': None})
In [323]: getattr(args, '-xxx$3')                                                                    
Out[323]: 'xxx'
In [324]: parser.print_usage()                                                                       
usage: ipython3 [-h] [--a-string MY-STRING] YOUR-STRING

Некоторые утверждали что позиционеры должны выполнять замену '- / _'. Но поскольку metavar дает полный контроль над отображением справки, в этом нет необходимости. В лучшем случае, если бы вы просто заставили positionals вести себя немного больше как `optionals.

Ваши возможности с metavar более ограничены. Специальные символы могут испортить форматирование usage, особенно если используется длинное (многострочное) или с взаимоисключающими группами. Это форматирование довольно хрупкое.

...