Подтвердить что ты не робот

Как сделать аргумент необязательным в python argparse

Я хотел бы сделать эти вызовы работы myprog, а не другие.

$ python3 myprog.py -i infile -o outfile
$ python3 myprog.py -o outfile
$ python3 myprog.py -o
$ python3 myprog.py 

В частности, я хочу сделать это незаконным, чтобы указать infile, но не outfile.

В третьем случае предполагается имя по умолчанию для outfile, out.json. Во втором, третьем и четвертом случаях предполагается имя по умолчанию для входного файла "file.n.json", где n - целочисленный номер версии. В четвертом случае выходной файл будет "file.n + 1.json", где n + 1 - это номер версии, который больше, чем номер входного файла. Соответствующий раздел моего кода:

import argparse

parser = argparse.ArgumentParser(description="first python version")
parser.add_argument('-i', '--infile', nargs=1, type=argparse.FileType('r'), help='input file, in JSON format')
parser.add_argument('-o', '--outfile', nargs='?', type=argparse.FileType('w'), default='out.json', help='output file, in JSON format')

args = parser.parse_args()

print("Here what we saw on the command line: ")
print("args.infile",args.infile)
print("args.outfile",args.outfile)

if args.infile and not args.outfile:
    parser.error("dont specify an infile without specifying an outfile")
elif not args.infile:
    print("fetching infile")
else: # neither was specified on the command line
    print("fetching both infile and outfile")

Проблема в том, что при запуске

$ python3 myprog.py -i infile.json

вместо ошибки парсера, на которую я надеялся, я получаю:

Here what we saw on the command line: 
args.infile [<_io.TextIOWrapper name='infile.json' mode='r' encoding='UTF-8'>]
args.outfile <_io.TextIOWrapper name='out.json' mode='w' encoding='UTF-8'>
fetching both infile and outfile

..., который предполагает, что, хотя в командной строке не было "-o", оно действовало так, как будто было.

4b9b3361

Ответ 1

Вы указали аргумент по умолчанию для outfile.

parser.add_argument('-o', '--outfile', nargs='?', type=argparse.FileType('w'), default='out.json', help='output file, in JSON format')

Если параметр -o не указан в командной строке, парсер arg вставляет аргумент по умолчанию.

Измените это на:

parser.add_argument('-o', '--outfile', nargs='?', type=argparse.FileType('w'), help='output file, in JSON format')

и все должно работать так, как вы ожидаете.


Если вы хотите указать -o, без имени файла, вы, вероятно, захотите что-то вроде:

out_file = args.out if args.out is not None else 'json.out'

Я не уверен, что соответствующий параметр будет None или '' (т.е. пустая строка), если вы укажете -o без параметра - я подозреваю, что он None, но я не знаю, я точно знаю. Вы должны проверить это, чтобы быть уверенным.

Я не знаю, как это сделать без дополнительной логики с помощью argparse.

Ответ 2

В качестве дополнения к выбранному ответу:

Возможность запуска -o без указания файла может быть выполнена с помощью const в сочетании с nargs='?'.

Из документов:

Когда add_argument() вызывается с помощью строк параметров (например, -f или --foo) и nargs = '?'. Это создает необязательный аргумент, который может соблюдаться по нулевому или одному аргументу командной строки. При анализе командной строки, если строка опций встречается без аргумента командной строки после него вместо этого предполагается значение const. См. Описание nargs для примеров.