Как добавить несколько аргументов argparse

PythonBeginner
Практиковаться сейчас

Введение

Этот учебник рассматривает, как добавлять и управлять несколькими аргументами командной строки в Python с использованием модуля argparse. Аргументы командной строки позволяют пользователям настраивать запуск программ без изменения самого кода. Модуль argparse упрощает этот процесс, предоставляя инструменты для определения, проверки и разбора этих аргументов.

К концу этого учебника вы поймете, как создавать Python-скрипты, которые могут принимать различные входные параметры, делая ваши приложения более гибкими и удобными для пользователя.

Основы работы с Argparse

Первый шаг в работе с аргументами командной строки — это понимание основ модуля argparse.

Что такое Argparse?

Argparse — это встроенный модуль Python, который упрощает написание удобных для пользователя интерфейсов командной строки. Он автоматически генерирует сообщения справки, обрабатывает ошибки и преобразует аргументы командной строки в соответствующие типы данных для вашей программы.

Создание вашего первого скрипта с использованием Argparse

Давайте начнем с создания простого Python-скрипта, который использует argparse. Мы создадим файл с именем hello.py, который принимает имя в качестве аргумента командной строки.

  1. Откройте редактор VSCode и создайте новый файл, нажав "File" > "New File"
  2. Сохраните файл как hello.py в каталоге /home/labex/project
  3. Добавьте следующий код в файл:
import argparse

## Create the parser
parser = argparse.ArgumentParser(description='A simple greeting program')

## Add an argument
parser.add_argument('--name', type=str, default='World', help='Name to greet')

## Parse the arguments
args = parser.parse_args()

## Use the argument
print(f"Hello, {args.name}!")

Этот скрипт демонстрирует три основных шага использования argparse:

  1. Создание объекта ArgumentParser
  2. Добавление аргументов в парсер
  3. Разбор аргументов командной строки

Запуск вашего скрипта

Давайте запустим скрипт, чтобы увидеть, как он работает:

  1. Откройте терминал в интерфейсе VSCode (Terminal > New Terminal)
  2. Запустите скрипт следующей командой:
python3 hello.py

Вы должны увидеть следующий вывод:

Hello, World!

Теперь давайте попробуем передать имя:

python3 hello.py --name Alice

Вывод:

Hello, Alice!

Понимание сообщений справки

Одним из преимуществ argparse является то, что он автоматически генерирует сообщения справки. Попробуйте запустить:

python3 hello.py --help

Вы должны увидеть вывод, похожий на:

usage: hello.py [-h] [--name NAME]

A simple greeting program

options:
  -h, --help   show this help message and exit
  --name NAME  Name to greet

Это сообщение справки автоматически генерируется на основе описания, которое мы предоставили при создании парсера, и текста справки, который мы добавили к нашему аргументу.

Ключевые компоненты Argparse

Давайте рассмотрим основные компоненты в нашем скрипте:

  • parser = argparse.ArgumentParser(description='...'): Создает парсер с описанием
  • parser.add_argument('--name', ...): Добавляет аргумент с именем '--name'
  • type=str: Указывает, что аргумент должен быть строкой
  • default='World': Устанавливает значение по умолчанию, если аргумент не предоставлен
  • help='Name to greet': Предоставляет текст справки для аргумента
  • args = parser.parse_args(): Разбирает аргументы командной строки
  • args.name: Получает доступ к значению аргумента 'name'

Теперь вы понимаете основы использования argparse для обработки аргументов командной строки в Python.

Добавление нескольких типов аргументов

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

Типы аргументов

Argparse поддерживает несколько типов аргументов:

  1. Позиционные аргументы (Positional arguments): Обязательные аргументы, идентифицируемые по их позиции
  2. Необязательные аргументы (Optional arguments): Аргументы с префиксом -- (или -), которые могут иметь значения по умолчанию
  3. Флаговые аргументы (Flag arguments): Булевы аргументы, которые либо присутствуют, либо отсутствуют
  4. Аргументы с вариантами (Arguments with choices): Аргументы, ограниченные определенными значениями

Давайте создадим новый скрипт, который демонстрирует эти различные типы аргументов.

  1. Создайте новый файл с именем calculator.py в каталоге /home/labex/project
  2. Добавьте следующий код:
import argparse

## Create the parser
parser = argparse.ArgumentParser(description='A simple calculator')

## Add a positional argument
parser.add_argument('operation',
                    choices=['add', 'subtract', 'multiply', 'divide'],
                    help='Math operation to perform')

## Add optional arguments
parser.add_argument('--num1', type=float, required=True,
                    help='First number')
parser.add_argument('--num2', type=float, required=True,
                    help='Second number')

## Add a flag argument
parser.add_argument('--verbose', action='store_true',
                    help='Enable verbose output')

## Parse the arguments
args = parser.parse_args()

## Perform the calculation based on the operation
result = 0
if args.operation == 'add':
    result = args.num1 + args.num2
elif args.operation == 'subtract':
    result = args.num1 - args.num2
elif args.operation == 'multiply':
    result = args.num1 * args.num2
elif args.operation == 'divide':
    if args.num2 == 0:
        print("Error: Cannot divide by zero")
        exit(1)
    result = args.num1 / args.num2

## Display the result
if args.verbose:
    print(f"The result of {args.num1} {args.operation} {args.num2} is: {result}")
else:
    print(f"Result: {result}")

Понимание новых аргументов

Давайте рассмотрим новые типы аргументов в этом скрипте:

  1. Позиционный аргумент: operation - должен быть одним из 'add', 'subtract', 'multiply' или 'divide'

    parser.add_argument('operation',
                        choices=['add', 'subtract', 'multiply', 'divide'],
                        help='Math operation to perform')
  2. Необязательные аргументы с required=True: --num1 и --num2 - должны быть предоставлены пользователем

    parser.add_argument('--num1', type=float, required=True,
                        help='First number')
  3. Флаговый аргумент: --verbose - при наличии включает подробный вывод

    parser.add_argument('--verbose', action='store_true',
                        help='Enable verbose output')

Тестирование калькулятора

Запустите калькулятор с разными аргументами, чтобы увидеть, как он работает:

python3 calculator.py add --num1 5 --num2 3

Вывод:

Result: 8.0

Попробуйте с флагом verbose:

python3 calculator.py multiply --num1 4 --num2 7 --verbose

Вывод:

The result of 4.0 multiply 7.0 is: 28.0

Попробуйте операцию деления:

python3 calculator.py divide --num1 10 --num2 2

Вывод:

Result: 5.0

Если вы забудете обязательный аргумент, argparse покажет ошибку:

python3 calculator.py add --num1 5

Вывод:

usage: calculator.py [-h] [--num1 NUM1] [--num2 NUM2] [--verbose]
                    {add,subtract,multiply,divide}
calculator.py: error: the following arguments are required: --num2

Ключевые моменты о типах аргументов

  • Позиционные аргументы (Positional arguments) не требуют префикса и идентифицируются по их позиции
  • Параметр choices ограничивает допустимые значения для аргумента
  • Параметр required=True делает необязательный аргумент обязательным
  • Параметр action='store_true' создает флаг, который по умолчанию равен False и становится True, когда указан
  • Параметр type преобразует ввод в указанный тип (float в нашем примере)

Теперь вы понимаете, как использовать различные типы аргументов с argparse.

Расширенные конфигурации аргументов

Теперь давайте рассмотрим более продвинутые конфигурации для аргументов, включая:

  1. Аргументы, принимающие несколько значений
  2. Аргументы с пользовательской проверкой
  3. Аргументы со значениями по умолчанию
  4. Аргументы с короткими именами (однобуквенные псевдонимы)

Создание скрипта обработки файлов

Давайте создадим скрипт, который демонстрирует эти расширенные конфигурации, построив утилиту обработки файлов.

  1. Создайте новый файл с именем file_processor.py в каталоге /home/labex/project
  2. Добавьте следующий код:
import argparse
import os

def validate_file(filename):
    """Validate that the file exists."""
    if not os.path.exists(filename):
        raise argparse.ArgumentTypeError(f"File {filename} does not exist")
    return filename

## Create the parser
parser = argparse.ArgumentParser(description='Process text files')

## Multiple values
parser.add_argument('-f', '--files',
                    type=validate_file,
                    nargs='+',
                    help='Input files to process')

## Argument with short name
parser.add_argument('-o', '--output',
                    default='output.txt',
                    help='Output file (default: output.txt)')

## Choices with default
parser.add_argument('-m', '--mode',
                    choices=['read', 'count', 'stats'],
                    default='read',
                    help='Processing mode (default: read)')

## Custom validation for a positive integer
def positive_int(value):
    ivalue = int(value)
    if ivalue <= 0:
        raise argparse.ArgumentTypeError(f"{value} is not a positive integer")
    return ivalue

parser.add_argument('-l', '--lines',
                    type=positive_int,
                    default=10,
                    help='Number of lines to process (default: 10)')

## Parse arguments
args = parser.parse_args()

## Process files based on mode
for file in args.files if args.files else []:
    print(f"Processing file: {file}")

    with open(file, 'r') as f:
        content = f.readlines()

        if args.mode == 'read':
            ## Read mode: output first N lines
            print(f"First {args.lines} lines:")
            for i, line in enumerate(content[:args.lines]):
                print(f"{i+1}: {line.strip()}")

        elif args.mode == 'count':
            ## Count mode: count lines, words, chars
            line_count = len(content)
            word_count = sum(len(line.split()) for line in content)
            char_count = sum(len(line) for line in content)

            print(f"Lines: {line_count}")
            print(f"Words: {word_count}")
            print(f"Characters: {char_count}")

        elif args.mode == 'stats':
            ## Stats mode: line length statistics
            if content:
                line_lengths = [len(line.strip()) for line in content]
                avg_length = sum(line_lengths) / len(line_lengths)
                max_length = max(line_lengths)
                min_length = min(line_lengths)

                print(f"Average line length: {avg_length:.2f}")
                print(f"Shortest line: {min_length} characters")
                print(f"Longest line: {max_length} characters")
            else:
                print("File is empty")

    print("-" * 30)

print(f"Results will be saved to: {args.output}")
## Note: In a real application, we would actually write to the output file

Понимание расширенных конфигураций

Давайте рассмотрим расширенные конфигурации аргументов:

  1. Несколько значений с nargs='+':

    parser.add_argument('-f', '--files',
                        type=validate_file,
                        nargs='+',
                        help='Input files to process')

    Параметр nargs='+' позволяет пользователю предоставить один или несколько аргументов файла.

  2. Пользовательская функция проверки:

    def validate_file(filename):
        if not os.path.exists(filename):
            raise argparse.ArgumentTypeError(f"File {filename} does not exist")
        return filename

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

  3. Короткие псевдонимы с -o:

    parser.add_argument('-o', '--output',
                        default='output.txt',
                        help='Output file (default: output.txt)')

    -o предоставляет более короткий способ указать аргумент --output.

  4. Варианты со значением по умолчанию:

    parser.add_argument('-m', '--mode',
                        choices=['read', 'count', 'stats'],
                        default='read',
                        help='Processing mode (default: read)')

    Это ограничивает режим определенными значениями, предоставляя при этом значение по умолчанию.

Создание тестовых файлов

Давайте создадим два тестовых файла для проверки нашего скрипта:

  1. Создайте образец файла с именем sample1.txt:
echo -e "This is the first line.\nThis is the second line.\nThis is the third line.\nThis is the fourth line.\nThis is the fifth line." > /home/labex/project/sample1.txt
  1. Создайте другой образец файла с именем sample2.txt:
echo -e "Lorem ipsum dolor sit amet.\nConsectetur adipiscing elit.\nSed do eiusmod tempor incididunt.\nUt labore et dolore magna aliqua." > /home/labex/project/sample2.txt

Тестирование обработчика файлов

Теперь давайте запустим скрипт с разными аргументами:

  1. Основное использование с одним файлом:
python3 file_processor.py -f sample1.txt

Вывод:

Processing file: sample1.txt
First 10 lines:
1: This is the first line.
2: This is the second line.
3: This is the third line.
4: This is the fourth line.
5: This is the fifth line.
------------------------------
Results will be saved to: output.txt
  1. Обработка нескольких файлов:
python3 file_processor.py -f sample1.txt sample2.txt

Вывод:

Processing file: sample1.txt
First 10 lines:
1: This is the first line.
2: This is the second line.
3: This is the third line.
4: This is the fourth line.
5: This is the fifth line.
------------------------------
Processing file: sample2.txt
First 10 lines:
1: Lorem ipsum dolor sit amet.
2: Consectetur adipiscing elit.
3: Sed do eiusmod tempor incididunt.
4: Ut labore et dolore magna aliqua.
------------------------------
Results will be saved to: output.txt
  1. Использование режима count:
python3 file_processor.py -f sample1.txt -m count

Вывод:

Processing file: sample1.txt
Lines: 5
Words: 25
Characters: 135
------------------------------
Results will be saved to: output.txt
  1. Использование режима stats:
python3 file_processor.py -f sample2.txt -m stats

Вывод:

Processing file: sample2.txt
Average line length: 29.25
Shortest line: 22 characters
Longest line: 37 characters
------------------------------
Results will be saved to: output.txt
  1. Ограничение количества строк:
python3 file_processor.py -f sample1.txt -l 2

Вывод:

Processing file: sample1.txt
First 2 lines:
1: This is the first line.
2: This is the second line.
------------------------------
Results will be saved to: output.txt

Ключевые моменты о расширенных конфигурациях

  • nargs='+' позволяет использовать несколько значений аргументов
  • Пользовательские функции проверки помогают обеспечить правильность ввода
  • Короткие имена аргументов (однобуквенные псевдонимы) обеспечивают удобство
  • Значения по умолчанию упрощают использование для распространенных сценариев
  • Параметр choices ограничивает ввод допустимыми параметрами

Теперь вы узнали, как настроить расширенные параметры аргументов в ваших скриптах командной строки.

Создание полноценного инструмента командной строки

На этом этапе мы объединим все, что узнали, чтобы создать полноценный инструмент командной строки. Давайте создадим простой менеджер задач, который позволит пользователям добавлять, просматривать и удалять задачи, используя аргументы командной строки.

Создание менеджера задач

  1. Создайте новый файл с именем task_manager.py в каталоге /home/labex/project
  2. Добавьте следующий код:
import argparse
import json
import os

## File to store tasks
TASKS_FILE = "/home/labex/project/tasks.json"

def load_tasks():
    """Load tasks from the JSON file."""
    if os.path.exists(TASKS_FILE):
        with open(TASKS_FILE, 'r') as f:
            try:
                return json.load(f)
            except json.JSONDecodeError:
                return []
    return []

def save_tasks(tasks):
    """Save tasks to the JSON file."""
    with open(TASKS_FILE, 'w') as f:
        json.dump(tasks, f, indent=2)

def main():
    ## Create the main parser
    parser = argparse.ArgumentParser(description='Task Manager CLI')
    subparsers = parser.add_subparsers(dest='command', help='Command to run')

    ## Add command
    add_parser = subparsers.add_parser('add', help='Add a new task')
    add_parser.add_argument('title', help='Task title')
    add_parser.add_argument('-p', '--priority',
                          choices=['low', 'medium', 'high'],
                          default='medium',
                          help='Task priority (default: medium)')
    add_parser.add_argument('-d', '--due',
                          help='Due date (format: YYYY-MM-DD)')

    ## List command
    list_parser = subparsers.add_parser('list', help='List all tasks')
    list_parser.add_argument('-p', '--priority',
                           choices=['low', 'medium', 'high'],
                           help='Filter tasks by priority')
    list_parser.add_argument('-s', '--sort',
                           choices=['priority', 'title'],
                           default='priority',
                           help='Sort tasks by criteria (default: priority)')

    ## Delete command
    delete_parser = subparsers.add_parser('delete', help='Delete a task')
    delete_parser.add_argument('task_id', type=int, help='Task ID to delete')

    ## Parse arguments
    args = parser.parse_args()

    ## Load existing tasks
    tasks = load_tasks()

    ## Handle commands
    if args.command == 'add':
        ## Add a new task
        new_task = {
            'id': len(tasks) + 1,
            'title': args.title,
            'priority': args.priority,
            'due': args.due
        }
        tasks.append(new_task)
        save_tasks(tasks)
        print(f"Task added: {new_task['title']} (ID: {new_task['id']})")

    elif args.command == 'list':
        ## List tasks
        if not tasks:
            print("No tasks found.")
            return

        ## Filter by priority if specified
        if args.priority:
            filtered_tasks = [t for t in tasks if t['priority'] == args.priority]
        else:
            filtered_tasks = tasks

        ## Sort tasks
        if args.sort == 'priority':
            ## Custom priority sorting
            priority_order = {'high': 0, 'medium': 1, 'low': 2}
            sorted_tasks = sorted(filtered_tasks, key=lambda x: priority_order[x['priority']])
        else:
            ## Sort by title
            sorted_tasks = sorted(filtered_tasks, key=lambda x: x['title'])

        ## Display tasks
        print("ID | Title                 | Priority | Due Date")
        print("-" * 50)
        for task in sorted_tasks:
            due_date = task['due'] if task['due'] else 'N/A'
            print(f"{task['id']:2} | {task['title'][:20]:<20} | {task['priority']:<8} | {due_date}")

    elif args.command == 'delete':
        ## Delete a task
        task_id = args.task_id
        task_found = False

        for i, task in enumerate(tasks):
            if task['id'] == task_id:
                del tasks[i]
                task_found = True
                break

        if task_found:
            save_tasks(tasks)
            print(f"Task {task_id} deleted.")
        else:
            print(f"Task {task_id} not found.")

    else:
        ## No command specified
        parser.print_help()

if __name__ == "__main__":
    main()

Понимание менеджера задач

Этот скрипт демонстрирует несколько расширенных функций argparse:

  1. Subparsers (Подпарсеры) - Создание наборов аргументов, специфичных для команд
  2. Command-specific arguments (Аргументы, специфичные для команд) - Различные аргументы для команд add, list и delete
  3. Nested validation (Вложенная проверка) - Выбор приоритета ограничен определенными значениями
  4. Default values (Значения по умолчанию) - Предоставление разумных значений по умолчанию для необязательных аргументов

Тестирование менеджера задач

Давайте запустим скрипт с разными командами, чтобы увидеть, как он работает:

  1. Добавление задач:
python3 task_manager.py add "Complete Python tutorial" -p high -d 2023-12-31

Вывод:

Task added: Complete Python tutorial (ID: 1)

Добавьте еще несколько задач:

python3 task_manager.py add "Read documentation" -p medium
python3 task_manager.py add "Take a break" -p low -d 2023-12-25
  1. Просмотр задач:
python3 task_manager.py list

Вывод:

ID | Title                 | Priority | Due Date
--------------------------------------------------
1  | Complete Python tutor | high     | 2023-12-31
2  | Read documentation    | medium   | N/A
3  | Take a break          | low      | 2023-12-25
  1. Просмотр задач с фильтрацией и сортировкой:
python3 task_manager.py list -s title

Вывод:

ID | Title                 | Priority | Due Date
--------------------------------------------------
1  | Complete Python tutor | high     | 2023-12-31
2  | Read documentation    | medium   | N/A
3  | Take a break          | low      | 2023-12-25
  1. Фильтрация по приоритету:
python3 task_manager.py list -p high

Вывод:

ID | Title                 | Priority | Due Date
--------------------------------------------------
1  | Complete Python tutor | high     | 2023-12-31
  1. Удаление задачи:
python3 task_manager.py delete 2

Вывод:

Task 2 deleted.

Убедитесь, что задача была удалена:

python3 task_manager.py list

Вывод:

ID | Title                 | Priority | Due Date
--------------------------------------------------
1  | Complete Python tutor | high     | 2023-12-31
3  | Take a break          | low      | 2023-12-25

Получение справки по подкомандам

Argparse автоматически генерирует справку для каждой подкоманды:

python3 task_manager.py add --help

Вывод:

usage: task_manager.py add [-h] [-p {low,medium,high}] [-d DUE] title

positional arguments:
  title                 Task title

options:
  -h, --help            show this help message and exit
  -p {low,medium,high}, --priority {low,medium,high}
                        Task priority (default: medium)
  -d DUE, --due DUE     Due date (format: YYYY-MM-DD)

Ключевые моменты о подпарсерах

  • Subparsers (Подпарсеры) создают наборы аргументов, специфичные для команд
  • Каждый подпарсер может иметь свои собственные аргументы
  • Параметр dest указывает, где будет храниться имя команды
  • Сообщения справки автоматически генерируются для каждой подкоманды
  • Вы можете смешивать позиционные и необязательные аргументы в подпарсерах

Теперь у вас есть полностью функциональный инструмент командной строки, который демонстрирует мощь и гибкость argparse для обработки сложных сценариев аргументов.

Резюме

В этом руководстве вы узнали, как использовать модуль argparse Python для эффективной обработки аргументов командной строки. Вы изучили:

  • Основные функции argparse и создание простых скриптов
  • Различные типы аргументов: позиционные, необязательные, флаги и варианты выбора
  • Расширенные конфигурации аргументов, такие как несколько значений и пользовательская проверка
  • Создание полноценного инструмента командной строки с подкомандами

Эти навыки позволяют создавать более гибкие и удобные для пользователя приложения Python, которые можно настраивать с помощью аргументов командной строки без изменения кода.

Разбор аргументов командной строки - важный навык для разработчиков Python, которые хотят создавать инструменты и утилиты профессионального качества. Модуль argparse предоставляет надежный и стандартизированный способ реализации этой функциональности в ваших скриптах.

Теперь вы можете применить эти методы к своим собственным проектам Python, чтобы сделать их более универсальными и доступными для пользователей.