Обработка внешних аргументов при запуске Python-скрипта
Работа с sys.argv в Python
Как получить список аргументов командной строки в Python?
Основной способ получения аргументов
Модуль sys предоставляет список argv, который содержит все переданные при запуске скрипта аргументы. Первый элемент (sys.argv[0]) это имя самого скрипта, остальные переданные аргументы.
import sys
print("Имя скрипта:", sys.argv[0])
print("Аргументы:", sys.argv[1:])Python параметр скрипта (параметры командной строки скрипта python (sys.argv))
Запуск python script.py arg1 arg2 выведет:
Имя скрипта: script.py Аргументы: ['arg1', 'arg2']
Пояснение: после импорта sys переменная sys.argv доступна. Срез sys.argv[1:] возвращает только переданные пользователем аргументы без имени скрипта. Это полезно для базовых сценариев, когда требуется просто получить значения позиционных параметров.
Типичные проблемы и их решения
Проблема: обращение к sys.argv[1] без проверки наличия аргументов вызывает IndexError. Решение: проверять длину len(sys.argv) перед доступом.
Проблема: все аргументы являются строками, даже числа. Решение: преобразовывать с помощью int() или float() с обработкой исключения ValueError.
Как использовать именованные аргументы (флаги) в командной строке?
Для сложных сценариев удобен модуль argparse. Он автоматически генерирует справку, обрабатывает типы и значения по умолчанию.
import argparse
parser = argparse.ArgumentParser(description="Пример использования argparse")
parser.add_argument("--input", help="Путь к входному файлу")
parser.add_argument("--output", default="out.txt", help="Путь к выходному файлу")
parser.add_argument("-v", "--verbose", action="store_true", help="Подробный вывод")
args = parser.parse_args()
print("Input:", args.input)
print("Output:", args.output)
print("Verbose:", args.verbose)
Пояснение: add_argument определяет аргументы. Для коротких флагов используется одна черта, для длинных две. action="store_true" делает флаг булевым. Запуск python app.py --input data.txt -v выведет соответствующие значения.
Проблема: неправильное имя аргумента, отсутствие обязательных. Решение: указывать required=True для обязательных аргументов.
Как без сторонних библиотек разобрать ключи вида -f или --file?
Можно написать простой парсер, перебирая sys.argv вручную.
import sys
args = sys.argv[1:]
options = {}
i = 0
while i < len(args):
if args[i].startswith('--'):
opt = args[i][2:]
if i+1 < len(args) and not args[i+1].startswith('-'):
options[opt] = args[i+1]
i += 2
else:
options[opt] = True
i += 1
elif args[i].startswith('-'):
opt = args[i][1:]
if i+1 < len(args) and not args[i+1].startswith('-'):
options[opt] = args[i+1]
i += 2
else:
options[opt] = True
i += 1
else:
options.setdefault('positional', []).append(args[i])
i += 1
print(options)
Этот код обрабатывает как -f file, так и --verbose без значения. Позиционные аргументы собираются в список под ключом positional.
Проблема: не обрабатываются объединённые короткие ключи (-abc). Решение: усложнение парсера или переход на argparse.
Как использовать модуль getopt для разбора аргументов?
Модуль getopt старый, но иногда полезен. Он требует указать ожидаемые опции.
import sys, getopt
try:
opts, args = getopt.getopt(sys.argv[1:], "hi:o:", ["help", "input=", "output="])
except getopt.GetoptError as err:
print(err)
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
print("Справка")
elif opt in ("-i", "--input"):
print("Input:", arg)
elif opt in ("-o", "--output"):
print("Output:", arg)
print("Остальные аргументы:", args)
Пояснение: строка "hi:o:" определяет короткие опции: h без значения, i и o с обязательным значением (двоеточие). Длинные опции задаются списком, для опций со значением добавляется =. Запуск python app.py -i input.txt -o output.txt обработается корректно.
Проблема: getopt не поддерживает длинные опции без значений (флаги) легко. Решение: указывать в строке опций без двоеточия для флагов, а в списке без =.
Дополнительные примеры работы с аргументами командной строки
Пример 1: Калькулятор с поддержкой операций
Скрипт принимает числа и опционально операцию (sum, average, product). Используется argparse с nargs='+'.
import sys, argparse
parser = argparse.ArgumentParser(description='Простой калькулятор')
parser.add_argument('numbers', nargs='+', type=float, help='Числа для вычисления')
parser.add_argument('--operation', choices=['sum', 'average', 'product'], default='sum', help='Операция')
args = parser.parse_args()
if args.operation == 'sum':
result = sum(args.numbers)
elif args.operation == 'average':
result = sum(args.numbers) / len(args.numbers)
elif args.operation == 'product':
result = 1
for n in args.numbers:
result *= n
print(f'Результат: {result}')
Результаты выполнения:
$ python calc.py 3 5 7 --operation sum Результат: 15.0 $ python calc.py 3 5 7 --operation average Результат: 5.0 $ python calc.py 3 5 7 --operation product Результат: 105.0
Пояснение: nargs='+' означает один или более аргументов. type=float автоматически преобразует строки в числа. choices ограничивает допустимые значения опции.
Пример 2: Подкоманды (subparsers) как в Git
Использование вложенных парсеров для реализации команд add, list и т.д.
import argparse
parser = argparse.ArgumentParser(description='Утилита для работы с данными')
subparsers = parser.add_subparsers(dest='command', required=True)
parser_add = subparsers.add_parser('add', help='Добавить запись')
parser_add.add_argument('name', help='Имя')
parser_add.add_argument('--age', type=int, default=0, help='Возраст')
parser_list = subparsers.add_parser('list', help='Показать записи')
parser_list.add_argument('--sort', choices=['name', 'age'], default='name', help='Поле сортировки')
args = parser.parse_args()
if args.command == 'add':
print(f'Добавлен {args.name}, возраст {args.age}')
elif args.command == 'list':
print(f'Вывод списка, сортировка по {args.sort}')
Результаты:
$ python app.py add Alice --age 30 Добавлен Alice, возраст 30 $ python app.py list --sort age Вывод списка, сортировка по age
Пояснение: subparsers создаёт отдельные группы аргументов для каждой команды. Аргумент dest='command' сохраняет имя команды.
Пример 3: Аргументы из переменной окружения или файла по умолчанию
Скрипт пытается получить значение из аргумента командной строки, затем из переменной окружения, затем использует значение по умолчанию.
import os, sys, argparse
parser = argparse.ArgumentParser()
parser.add_argument('--config', help='Путь к файлу конфигурации')
args, unknown = parser.parse_known_args()
config_file = args.config or os.environ.get('APP_CONFIG', 'config.ini')
print(f'Используется конфиг: {config_file}')
Результаты:
$ python app.py Используется конфиг: config.ini $ APP_CONFIG=/etc/app/config.ini python app.py Используется конфиг: /etc/app/config.ini $ python app.py --config /tmp/custom.ini Используется конфиг: /tmp/custom.ini
Пояснение: parse_known_args() игнорирует неизвестные аргументы. Оператор or выбирает первое непустое значение.
Пример 4: Разбор строки с экранированием (shlex)
Когда аргументы приходят в виде строки (например, из другого скрипта), удобно использовать shlex.split().
import sys, shlex
# Имитация строки аргументов
cmdline = 'program "hello world" --name="John Doe"'
args = shlex.split(cmdline)[1:] # убираем имя программы
print('Аргументы:', args)
# Теперь можно передать в любой парсер
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('message', nargs='?', default='default')
parser.add_argument('--name')
parsed = parser.parse_args(args)
print(parsed)
Результат:
Аргументы: ['hello world', '--name=John Doe'] Namespace(message='hello world', name='John Doe')
Пояснение: shlex.split() корректно обрабатывает кавычки и экранирование, возвращая список аргументов как если бы они были введены в терминале.
Пример 5: Переменное число позиционных аргументов (nargs='*')
Скрипт принимает любое количество файлов, по умолчанию использует stdin.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('files', nargs='*', type=str, default=['-'], help='Файлы для обработки (по умолчанию stdin)')
parser.add_argument('--output', '-o', default='out.txt')
args = parser.parse_args()
print('Обрабатываемые файлы:', args.files)
print('Вывод в:', args.output)
Результаты:
$ python process.py Обрабатываемые файлы: ['-'] Вывод в: out.txt $ python process.py a.txt b.txt --output result.txt Обрабатываемые файлы: ['a.txt', 'b.txt'] Вывод в: result.txt
Пояснение: nargs='*' принимает ноль или более аргументов. Значение default=['-'] используется, когда аргументы не переданы.