Проверьте, установлен ли необязательный аргумент argparse или нет

112

Я хотел бы проверить, установлен ли пользователем необязательный аргумент argparse или нет.

Могу ли я безопасно проверить с помощью isset?

Что-то вроде этого:

if(isset(args.myArg)):
    #do something
else:
    #do something else

Работает ли это так же для аргументов типа float / int / string?

Я мог бы установить параметр по умолчанию и проверить его (например, установить myArg = -1, или «» для строки, или «NOT_SET»). Однако значение, которое я в конечном итоге хочу использовать, вычисляется позже в сценарии. Поэтому я бы установил его на -1 по умолчанию, а затем обновил бы его на что-то другое позже. Это кажется немного неуклюжим по сравнению с простой проверкой того, было ли значение установлено пользователем.

Мадлен П. Винсент
источник
1
Что бы isset()было (подсказка: Python - это не PHP)? Возможно, вы имели в виду hasattr()вместо этого? Почему бы вместо этого не настроить argparse для установки параметра по умолчанию?
Мартин Питерс
@MartijnPieters - да, верно. Так что я могу просто проверить, если (args.myArg): ...
Мадлен П. Винсент

Ответы:

146

Я думаю, что необязательные аргументы (указанные с помощью --) инициализируются, Noneесли они не указаны. Так что вы можете протестировать с помощью is not None. Попробуйте пример ниже:

import argparse as ap

def main():
    parser = ap.ArgumentParser(description="My Script")
    parser.add_argument("--myArg")
    args, leftovers = parser.parse_known_args()

    if args.myArg is not None:
        print "myArg has been set (value is %s)" % args.myArg
Honza Osobne
источник
Тесты «Нет» и «Не Нет» работают точно так, как я хотел и ожидал. Спасибо.
Мадлен П. Винсент
39
К сожалению, это не работает, тогда аргумент получил defaultзначение.
kcpr
6
Если вы хотите установить a default, вы все равно можете установить nargs='?'и предоставить constзначение, как описано в документации . Когда arg отсутствует, defaultиспользуется, когда arg задано без значения, тогда constиспользуется, в противном случае используется заданное значение. С только defaultи nargs='?', defaultиспользуется , если не дано, Noneесли дано без значения, в противном случае данное значение.
Иоаннис Филиппидис
@IoannisFilippidis, если вы используете action= "store_true"или action="store_const", const="yourconst"не можете использовать этот аргумент для хранения другого значения. При использовании значений по умолчанию это не сработает. В моем собственном я удалил все значения по умолчанию из argparser и обработал все внутри другой функции, def defaults():где я смешиваю ConfigParser, ArgumentParser и значения по умолчанию в том порядке, в котором я хочу
m3nda
@ erm3nda Я не упоминал о настройке action. В ответе не используется расширение action. Упомянутые вами действия задокументированы, чтобы вести себя одним определенным образом (как вы заметили). Однако необязательно определять действие.
Иоаннис Филиппидис
37

Как отмечает @Honza, is Noneэто хороший тест. Это значение по умолчанию default, и пользователь не может дать вам строку, которая его дублирует.

Вы можете указать другой default='mydefaultvalueи проверить это. Но что, если пользователь указывает эту строку? Это считается настройкой или нет?

Вы также можете указать default=argparse.SUPPRESS. Затем, если пользователь не использует аргумент, он не появится в argsпространстве имен. Но тестирование может быть более сложным:

args.foo # raises an AttributeError
hasattr(args, 'foo')  # returns False
getattr(args, 'foo', 'other') # returns 'other'

Внутри parserхранится список seen_actionsи используется для «обязательного» и «взаимно исключающего» тестирования. Но он недоступен для вас извне parse_args.

hpaulj
источник
22

Я думаю, что использование этой опции default=argparse.SUPPRESSимеет наибольший смысл. Затем вместо проверки, является ли аргумент not None, проверяется, является ли аргумент inрезультирующим пространством имен.

Пример:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--foo", default=argparse.SUPPRESS)
ns = parser.parse_args()

print("Parsed arguments: {}".format(ns))
print("foo in namespace?: {}".format("foo" in ns))

Использование:

$ python argparse_test.py --foo 1
Parsed arguments: Namespace(foo='1')
foo in namespace?: True
Аргумент не предоставляется:
$ python argparse_test.py
Parsed arguments: Namespace()
foo in namespace?: False
Эразм Седернаес
источник
У меня это не работает под Python 3.7.5 (Anaconda). Я получаю результатtestfoo.py: error: argument --foo: expected one argument
Майк Уайз
@MikeWise Если вы хотите использовать --fooбез значения (например, 1в моем примере), вы должны указать nargs=0в add_argumentфункции.
Эразм Седернаес
Я просто скопировал и вставил ваш код, как указано в ответе. Может стоит отредактировать? В итоге я использовал action='store_true'ответ ниже в своем фактическом коде.
Майк Уайз,
@MikeWise вы запускали скрипт как python argparse_test.py --foo 1?
Эразм Седернаес,
11

Вы можете проверить необязательно переданный флаг с помощью параметров действия store_trueи store_falseаргумента:

import argparse

argparser = argparse.ArgumentParser()
argparser.add_argument('-flag', dest='flag_exists', action='store_true')

print argparser.parse_args([])
# Namespace(flag_exists=False)
print argparser.parse_args(['-flag'])
# Namespace(flag_exists=True)

Таким образом, вам не нужно беспокоиться о проверке по условию is not None. Вы просто проверяете Trueили False. Подробнее об этих параметрах читайте в документации здесь.

Гарри Сэдлер
источник
1
это не решает вопроса, установлен ли аргумент, имеющий значение, или нет. основная проблема здесь - узнать, происходит ли значение args от defaul = "" или оно предоставляется пользователем.
m3nda
5

Если ваш аргумент позиционный (то есть у него нет префикса «-» или «-», только аргумент, обычно имя файла), вы можете использовать параметр nargs для этого:

parser = argparse.ArgumentParser(description='Foo is a program that does things')
parser.add_argument('filename', nargs='?')
args = parser.parse_args()

if args.filename is not None:
    print('The file name is {}'.format(args.filename))
else:
    print('Oh well ; No args, no problems')
yPhil
источник
3

Вот мое решение, чтобы узнать, использую ли я переменную argparse

import argparse

ap = argparse.ArgumentParser()
ap.add_argument("-1", "--first", required=True)
ap.add_argument("-2", "--second", required=True)
ap.add_argument("-3", "--third", required=False) 
# Combine all arguments into a list called args
args = vars(ap.parse_args())
if args["third"] is not None:
# do something

Это может дать больше информации о приведенном выше ответе, который я использовал и адаптировал для работы в моей программе.

К.Рэдфорд
источник
0

Чтобы обратиться к комментарию @ kcpr к (принятому в настоящее время) ответу @Honza Osobne

К сожалению, это не работает, тогда аргумент получил значение по умолчанию.

сначала можно проверить, был ли предоставлен аргумент, сравнив его с Namespaceобъектом abd, предоставляющим default=argparse.SUPPRESSпараметр (см. ответы @ hpaulj и @Erasmus Cedernaes и этот документ python3 ), и, если он не был предоставлен, установите для него значение по умолчанию.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--infile', default=argparse.SUPPRESS)
args = parser.parse_args()
if 'infile' in args: 
    # the argument is in the namespace, it's been provided by the user
    # set it to what has been provided
    theinfile = args.infile
    print('argument \'--infile\' was given, set to {}'.format(theinfile))
else:
    # the argument isn't in the namespace
    # set it to a default value
    theinfile = 'your_default.txt'
    print('argument \'--infile\' was not given, set to default {}'.format(theinfile))

использование

$ python3 testargparse_so.py
argument '--infile' was not given, set to default your_default.txt

$ python3 testargparse_so.py --infile user_file.txt
argument '--infile' was given, set to user_file.txt
калокедрус
источник
0

Очень просто, после определения переменной args с помощью 'args = parser.parse_args ()' она также содержит все данные переменных подмножества args. Чтобы проверить, установлена ​​ли переменная или нет, при условии, что используется 'action = "store_true" ...

if args.argument_name:
   # do something
else:
   # do something else
вата287
источник