¿Argparse argumentos posicionales opcionales?

Resuelto Waldo Bronchart asked hace 13 años • 4 respuestas

Tengo un script que debe usarse así:

usage: installer.py dir [-h] [-v]

dires un argumento posicional que se define así:

parser.add_argument('dir', default=os.getcwd())

Quiero que dirsea opcional: cuando no esté especificado, debería ser simplemente cwd.

Desafortunadamente, cuando no especifico el dirargumento, aparece Error: Too few arguments.

Waldo Bronchart avatar Dec 19 '10 03:12 Waldo Bronchart
Aceptado

Utilice nargs='?'(o nargs='*'si necesita más de un directorio)

parser.add_argument('dir', nargs='?', default=os.getcwd())

ejemplo extendido:

>>> import os, argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('-v', action='store_true')
_StoreTrueAction(option_strings=['-v'], dest='v', nargs=0, const=True, default=False, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument('dir', nargs='?', default=os.getcwd())
_StoreAction(option_strings=[], dest='dir', nargs='?', const=None, default='/home/vinay', type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args('somedir -v'.split())
Namespace(dir='somedir', v=True)
>>> parser.parse_args('-v'.split())
Namespace(dir='/home/vinay', v=True)
>>> parser.parse_args(''.split())
Namespace(dir='/home/vinay', v=False)
>>> parser.parse_args(['somedir'])
Namespace(dir='somedir', v=False)
>>> parser.parse_args('somedir -h -v'.split())
usage: [-h] [-v] [dir]

positional arguments:
  dir

optional arguments:
  -h, --help  show this help message and exit
  -v
Vinay Sajip avatar Dec 18 '2010 21:12 Vinay Sajip

Como una extensión de la respuesta de @VinaySajip. Hay otros nargsque vale la pena mencionar .

  1. parser.add_argument('dir', nargs=1, default=os.getcwd())

N (un número entero). N argumentos de la línea de comando se reunirán en una lista

  1. parser.add_argument('dir', nargs='*', default=os.getcwd())

'*'. Todos los argumentos de la línea de comandos presentes se reúnen en una lista. Tenga en cuenta que generalmente no tiene mucho sentido tener más de un argumento posicional con nargs='*', pero nargs='*'es posible tener múltiples argumentos opcionales con.

  1. parser.add_argument('dir', nargs='+', default=os.getcwd())

'+'. Al igual que '*', todos los argumentos de la línea de comandos presentes se reúnen en una lista. Además, se generará un mensaje de error si no había al menos un argumento de línea de comando presente.

  1. parser.add_argument('dir', nargs=argparse.REMAINDER, default=os.getcwd())

argparse.REMAINDER. Todos los argumentos restantes de la línea de comandos se reúnen en una lista. Esto suele ser útil para utilidades de línea de comandos que se envían a otras utilidades de línea de comandos.

Si nargsno se proporciona el argumento de la palabra clave, la acción determina el número de argumentos consumidos. Generalmente, esto significa que se consumirá un único argumento de línea de comando y se producirá un solo elemento (no una lista).

Editar (copiado de un comentario de @Acumenus) nargs='?' Los documentos dicen: '?'. Si es posible, se consumirá un argumento desde la línea de comando y se producirá como un solo elemento. Si no hay ningún argumento de línea de comando presente, se generará el valor predeterminado.

Matas Vaitkevicius avatar Jul 06 '2015 10:07 Matas Vaitkevicius

Respuesta corta

Como ya se mostró en las dos respuestas anteriores, puede aceptar un argumento posicional opcional con nargs='?'. También podrías convertir el argumento directamente en un Pathtipo y/o acortar el cwd a .si quisieras:

miarchivo.py

import argparse
import pathlib

parser = argparse.ArgumentParser()
parser.add_argument("dir", nargs="?", default=".", type=pathlib.Path)
parsed_args = parser.parse_args()

print("Installing to", parsed_args.dir.resolve())
$ python myfile.py
Installing to /users/myname/myfolder

$ python myfile.py /usr/bin/
Installing to /usr/bin

respuesta más larga

Dado que también menciona las opciones Verdadero/Falso de estilo de bandera -hy -ven su pregunta, estos ejemplos pueden ser útiles:

Banderas (p. ej -v.)

Podríamos referirnos a opciones opcionales que no aceptan argumentos como "banderas". Con las banderas sólo nos importa si se dan o no. -hes una bandera que argparse agrega automáticamente (junto con la versión más larga --help), por lo que no deberíamos anularla. Si consideramos -ventonces,

miarchivo.py

import argparse

parser = argparse.ArgumentParser()
parser.add_argument(
        "-v",
        "--version",
        action="store_true")
parsed_args = parser.parse_args()

if parsed_args.version:
    print("version flag given")
else:
    print("version flag not given")

Tenga en cuenta que el segundo argumento add_argument()es un nombre más largo para la opción. No es obligatorio, pero hace que el código posterior sea más legible ( parsed_args.versionvs parsed_args.v) y hace que las llamadas al instalador sean más explícitas.

$ python myfile.py -v
version flag given

$ python myfile.py --version
version flag given

$ python myfile.py
version flag not given

Argumentos opcionales (p. ej. --installdir /usr/bin/)

Se podría argumentar que, en su caso, estaría mejor con un argumento opcional en lugar de uno posicional.

miarchivo.py

import argparse
import pathlib

parser = argparse.ArgumentParser()
parser.add_argument(
        "-i",
        "--installdir",  # Optional (but recommended) long version
        type=pathlib.Path,
        default="/bin"
        )
parsed_args = parser.parse_args()

print("Installing to", parsed_args.installdir)
$ python myfile.py -i /usr/bin/
Installing to /usr/bin

$ python myfile.py --installdir /usr/bin/
Installing to /usr/bin

$ python myfile.py
Installing to /bin
FiddleStix avatar Mar 14 '2022 14:03 FiddleStix