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.
También te puede interesar
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')
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.