¿Cómo agregar múltiples argumentos argparse?

PythonBeginner
Practicar Ahora

Introducción

Este tutorial explora cómo agregar y gestionar múltiples argumentos de línea de comandos en Python utilizando el módulo argparse. Los argumentos de línea de comandos permiten a los usuarios personalizar cómo se ejecutan los programas sin modificar el código en sí. El módulo argparse simplifica este proceso al proporcionar herramientas para definir, validar y analizar estos argumentos.

Al final de este tutorial, comprenderá cómo crear scripts de Python que pueden aceptar varios parámetros de entrada, haciendo que sus aplicaciones sean más flexibles y fáciles de usar.

Comprender los Fundamentos de Argparse

El primer paso para trabajar con argumentos de línea de comandos es comprender los fundamentos del módulo argparse.

¿Qué es Argparse?

Argparse es un módulo integrado de Python que facilita la escritura de interfaces de línea de comandos fáciles de usar. Genera automáticamente mensajes de ayuda, maneja errores y convierte los argumentos de línea de comandos a los tipos de datos apropiados para su programa.

Creando tu Primer Script con Argparse

Comencemos creando un script de Python simple que utiliza argparse. Crearemos un archivo llamado hello.py que acepta un nombre como argumento de línea de comandos.

  1. Abra el editor VSCode y cree un nuevo archivo haciendo clic en "Archivo" > "Nuevo archivo"
  2. Guarde el archivo como hello.py en el directorio /home/labex/project
  3. Agregue el siguiente código al archivo:
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}!")

Este script demuestra los tres pasos principales para usar argparse:

  1. Crear un objeto ArgumentParser
  2. Agregar argumentos al analizador (parser)
  3. Analizar los argumentos de la línea de comandos

Ejecutando tu Script

Ejecutemos el script para ver cómo funciona:

  1. Abra una terminal en la interfaz de VSCode (Terminal > Nueva terminal)
  2. Ejecute el script con el siguiente comando:
python3 hello.py

Debería ver esta salida:

Hello, World!

Ahora, intentemos pasar un nombre:

python3 hello.py --name Alice

Salida:

Hello, Alice!

Comprender los Mensajes de Ayuda

Uno de los beneficios de argparse es que genera automáticamente mensajes de ayuda. Intente ejecutar:

python3 hello.py --help

Debería ver una salida similar a:

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

A simple greeting program

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

Este mensaje de ayuda se genera automáticamente en función de la descripción que proporcionamos al crear el analizador y el texto de ayuda que agregamos a nuestro argumento.

Componentes Clave de Argparse

Examinemos los componentes principales de nuestro script:

  • parser = argparse.ArgumentParser(description='...'): Crea un analizador con una descripción
  • parser.add_argument('--name', ...): Agrega un argumento con el nombre '--name'
  • type=str: Especifica que el argumento debe ser una cadena (string)
  • default='World': Establece un valor predeterminado si no se proporciona el argumento
  • help='Name to greet': Proporciona texto de ayuda para el argumento
  • args = parser.parse_args(): Analiza los argumentos de la línea de comandos
  • args.name: Accede al valor del argumento 'name'

Ahora comprende los conceptos básicos del uso de argparse para manejar argumentos de línea de comandos en Python.

Agregar Múltiples Tipos de Argumentos

Ahora que comprende los conceptos básicos, exploremos los diferentes tipos de argumentos que se pueden agregar a su interfaz de línea de comandos.

Tipos de Argumentos

Argparse admite varios tipos de argumentos:

  1. Argumentos posicionales (Positional arguments): Argumentos requeridos identificados por su posición
  2. Argumentos opcionales (Optional arguments): Argumentos precedidos por -- (o -) que pueden tener valores predeterminados
  3. Argumentos de bandera (Flag arguments): Argumentos booleanos que están presentes o ausentes
  4. Argumentos con opciones (Arguments with choices): Argumentos limitados a valores específicos

Creemos un nuevo script que demuestre estos diferentes tipos de argumentos.

  1. Cree un nuevo archivo llamado calculator.py en el directorio /home/labex/project
  2. Agregue el siguiente código:
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}")

Comprender los Nuevos Argumentos

Examinemos los nuevos tipos de argumentos en este script:

  1. Argumento posicional: operation - debe ser uno de 'add', 'subtract', 'multiply' o 'divide'

    parser.add_argument('operation',
                        choices=['add', 'subtract', 'multiply', 'divide'],
                        help='Math operation to perform')
  2. Argumentos opcionales con required=True: --num1 y --num2 - deben ser proporcionados por el usuario

    parser.add_argument('--num1', type=float, required=True,
                        help='First number')
  3. Argumento de bandera: --verbose - cuando está presente, habilita la salida detallada

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

Probando la Calculadora

Ejecute la calculadora con diferentes argumentos para ver cómo funciona:

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

Salida:

Result: 8.0

Intente con la bandera verbose:

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

Salida:

The result of 4.0 multiply 7.0 is: 28.0

Intente la operación de división:

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

Salida:

Result: 5.0

Si olvida un argumento requerido, argparse mostrará un error:

python3 calculator.py add --num1 5

Salida:

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

Puntos Clave sobre los Tipos de Argumentos

  • Los argumentos posicionales (Positional arguments) no necesitan un prefijo y se identifican por su posición
  • El parámetro choices restringe los valores válidos para un argumento
  • El parámetro required=True hace que un argumento opcional sea obligatorio
  • El parámetro action='store_true' crea una bandera que es False de forma predeterminada y True cuando se especifica
  • El parámetro type convierte la entrada al tipo especificado (float en nuestro ejemplo)

Ahora comprende cómo usar diferentes tipos de argumentos con argparse.

Configuraciones Avanzadas de Argumentos

Ahora, exploremos configuraciones más avanzadas para los argumentos, incluyendo:

  1. Argumentos que aceptan múltiples valores
  2. Argumentos con validación personalizada
  3. Argumentos con valores predeterminados
  4. Argumentos con nombres cortos (alias de una sola letra)

Creando un Script de Procesamiento de Archivos

Creemos un script que demuestre estas configuraciones avanzadas construyendo una utilidad de procesamiento de archivos.

  1. Cree un nuevo archivo llamado file_processor.py en el directorio /home/labex/project
  2. Agregue el siguiente código:
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

Comprender las Configuraciones Avanzadas

Examinemos las configuraciones avanzadas de argumentos:

  1. Múltiples valores con nargs='+':

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

    El parámetro nargs='+' permite al usuario proporcionar uno o más argumentos de archivo.

  2. Función de validación personalizada:

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

    Esta función verifica si el archivo especificado existe antes de continuar.

  3. Alias cortos con -o:

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

    El -o proporciona una forma más corta de especificar el argumento --output.

  4. Opciones con valor predeterminado:

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

    Esto limita el modo a valores específicos mientras proporciona un valor predeterminado.

Creando Archivos de Prueba de Ejemplo

Creemos dos archivos de ejemplo para probar nuestro script:

  1. Cree un archivo de ejemplo llamado 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
  2. Cree otro archivo de ejemplo llamado 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

Probando el Procesador de Archivos

Ahora, ejecutemos el script con diferentes argumentos:

  1. Uso básico con un archivo:

    python3 file_processor.py -f sample1.txt

    Salida:

    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
  2. Procesar múltiples archivos:

    python3 file_processor.py -f sample1.txt sample2.txt

    Salida:

    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
  3. Usar el modo count:

    python3 file_processor.py -f sample1.txt -m count

    Salida:

    Processing file: sample1.txt
    Lines: 5
    Words: 25
    Characters: 135
    ------------------------------
    Results will be saved to: output.txt
  4. Usar el modo stats:

    python3 file_processor.py -f sample2.txt -m stats

    Salida:

    Processing file: sample2.txt
    Average line length: 29.25
    Shortest line: 22 characters
    Longest line: 37 characters
    ------------------------------
    Results will be saved to: output.txt
  5. Limitar el número de líneas:

    python3 file_processor.py -f sample1.txt -l 2

    Salida:

    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

Puntos Clave sobre las Configuraciones Avanzadas

  • nargs='+' permite múltiples valores de argumento
  • Las funciones de validación personalizadas ayudan a garantizar una entrada válida
  • Los nombres de argumentos cortos (alias de una sola letra) brindan conveniencia
  • Los valores predeterminados simplifican el uso para escenarios comunes
  • El parámetro choices restringe la entrada a opciones válidas

Ahora ha aprendido a configurar opciones de argumentos avanzadas en sus scripts de línea de comandos.

Construyendo una Herramienta de Línea de Comandos Completa

En este paso, combinaremos todo lo que hemos aprendido para construir una herramienta de línea de comandos completa. Creemos un administrador de tareas simple que permita a los usuarios agregar, listar y eliminar tareas utilizando argumentos de línea de comandos.

Creando el Administrador de Tareas

  1. Cree un nuevo archivo llamado task_manager.py en el directorio /home/labex/project
  2. Agregue el siguiente código:
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()

Comprender el Administrador de Tareas

Este script demuestra varias características avanzadas de argparse:

  1. Subparsers (Subparsers) - Creación de conjuntos de argumentos específicos para cada comando
  2. Argumentos específicos para cada comando (Command-specific arguments) - Diferentes argumentos para los comandos add, list y delete
  3. Validación anidada - Opciones de prioridad limitadas a valores específicos
  4. Valores predeterminados - Proporcionar valores predeterminados sensatos para argumentos opcionales

Probando el Administrador de Tareas

Ejecutemos el script con diferentes comandos para ver cómo funciona:

  1. Agregar tareas:

    python3 task_manager.py add "Complete Python tutorial" -p high -d 2023-12-31

    Salida:

    Task added: Complete Python tutorial (ID: 1)

    Agregue algunas tareas más:

    python3 task_manager.py add "Read documentation" -p medium
    python3 task_manager.py add "Take a break" -p low -d 2023-12-25
  2. Listar tareas:

    python3 task_manager.py list

    Salida:

    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
  3. Listar tareas con filtrado y ordenamiento:

    python3 task_manager.py list -s title

    Salida:

    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
  4. Filtrar por prioridad:

    python3 task_manager.py list -p high

    Salida:

    ID | Title                 | Priority | Due Date
    --------------------------------------------------
    1  | Complete Python tutor | high     | 2023-12-31
  5. Eliminar una tarea:

    python3 task_manager.py delete 2

    Salida:

    Task 2 deleted.

    Verifique que la tarea se eliminó:

    python3 task_manager.py list

    Salida:

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

Obtener Ayuda para Subcomandos

Argparse genera automáticamente ayuda para cada subcomando:

python3 task_manager.py add --help

Salida:

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)

Puntos Clave sobre los Subparsers

  • Los subparsers crean conjuntos de argumentos específicos para cada comando
  • Cada subparser puede tener sus propios argumentos
  • El parámetro dest especifica dónde se almacenará el nombre del comando
  • Los mensajes de ayuda se generan automáticamente para cada subcomando
  • Puede mezclar argumentos posicionales y opcionales en los subparsers

Ahora tiene una herramienta de línea de comandos completamente funcional que demuestra el poder y la flexibilidad de argparse para manejar escenarios de argumentos complejos.

Resumen

En este tutorial, aprendió a usar el módulo argparse de Python para manejar argumentos de línea de comandos de manera efectiva. Exploró:

  • La funcionalidad básica de argparse y la creación de scripts simples
  • Diferentes tipos de argumentos: posicionales, opcionales, flags (banderas) y opciones (choices)
  • Configuraciones avanzadas de argumentos como múltiples valores y validación personalizada
  • La construcción de una herramienta de línea de comandos completa con subcomandos

Estas habilidades le permiten crear aplicaciones Python más flexibles y fáciles de usar que se pueden configurar a través de argumentos de línea de comandos sin modificar el código.

El análisis de argumentos de línea de comandos es una habilidad esencial para los desarrolladores de Python que desean construir herramientas y utilidades de calidad profesional. El módulo argparse proporciona una forma robusta y estandarizada de implementar esta funcionalidad en sus scripts.

Ahora puede aplicar estas técnicas a sus propios proyectos de Python para hacerlos más versátiles y accesibles para los usuarios.