Argumentos de la línea de órdenes en Python con argparse

Python trae argparse en la biblioteca estándar, y hace solo casi todo: analiza, valida, genera la ayuda y sale con el código correcto cuando te equivocas. Escribir el analizador a mano con sys.argv casi nunca compensa.

Un analizador completo

import argparse
from pathlib import Path

p = argparse.ArgumentParser(
    prog="contar",
    description="Cuenta líneas, palabras y caracteres.",
    epilog="sin archivos lee de la entrada estándar")

p.add_argument("archivos", nargs="*", type=Path, help="archivos a contar")
p.add_argument("-l", "--lineas", action="store_true", help="solo líneas")
p.add_argument("-n", "--top", type=int, default=0, metavar="N",
               help="las N palabras más repetidas")
p.add_argument("--formato", choices=["texto", "json"], default="texto")
p.add_argument("-v", "--verboso", action="count", default=0,
               help="más detalle (se puede repetir: -vv)")
p.add_argument("--version", action="version", version="%(prog)s 1.0")

a = p.parse_args()
python3 contar.py -vv --top 5 --formato json a.txt b.txt
salidaarchivos=['a.txt', 'b.txt']
lineas=False palabras=False top=5
formato=json verboso=2

Fíjate en lo que ha hecho sin que se lo pidas: convirtió las rutas a objetos Path, el --top a entero, contó cuántas veces aparece -v, y dejó lo que no era opción en una lista.

Si quieres… Escribes
Una bandera de sí o no action="store_true"
Un valor convertido type=int, type=Path, type=float
Contar repeticiones (-vv) action="count", default=0
Solo ciertos valores choices=[...]
Varios argumentos sueltos nargs="*" o nargs="+"
Que sea obligatorio required=True
Poder repetir la opción action="append"

La ayuda la escribe él

contar --helpusage: contar [-h] [-l] [-p] [-n N] [--formato {texto,json}] [-v] [--version]
              [archivos ...]

Cuenta líneas, palabras y caracteres.

positional arguments:
  archivos              archivos a contar

options:
  -h, --help            show this help message and exit
  -l, --lineas          solo líneas
  -n, --top N           las N palabras más repetidas
  --formato {texto,json}
  -v, --verboso         más detalle (se puede repetir: -vv)
  --version             show program's version number and exit

sin archivos lee de la entrada estándar

Sale del description, del epilog y de cada help=. Esa es la razón principal para usar argparse: la ayuda no se queda desactualizada, porque es el mismo código.

Y los errores, también

código de salida 2contar: error: unrecognized arguments: --loquesea
código de salida 2contar: error: argument --formato: invalid choice: 'xml' (choose from 'texto', 'json')
Los códigos de salida ya son los correctos. argparse sale con 2 cuando lo llamas mal —que es la convención de Unix para «error de uso»— y con 0 tras --help o --version, porque pedir ayuda no es un fallo. Comprobado con echo $?.

Que se pueda probar

def main(argv=None):
    p = argparse.ArgumentParser(...)
    a = p.parse_args(argv)        # None = sys.argv[1:]
    ...
    return 0

if __name__ == "__main__":
    sys.exit(main())

Ese argv=None es el detalle que convierte la herramienta en algo probable: desde una prueba llamas main(["-n", "3", "fichero.txt"]) sin tocar sys.argv ni arrancar un proceso. Y devolver el código en vez de llamar a sys.exit dentro permite comprobarlo con un assert.

Subórdenes

sub = p.add_subparsers(dest="orden", required=True)

a = sub.add_parser("add", help="añade una tarea")
a.add_argument("texto")

b = sub.add_parser("list", help="muestra las tareas")
b.add_argument("-a", "--todas", action="store_true")

Cada suborden tiene sus propias opciones y su propia ayuda, como en git commit o docker run. Con required=True, llamar al programa sin ninguna da error en vez de seguir adelante.

Si el proyecto crece mucho, las alternativas habituales son Click y Typer, que montan el analizador a partir de la firma de tus funciones. Pero argparse no tiene dependencias y cubre más de lo que parece.

Todo el código se ejecutó con Python 3.14 en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.