¿Argparse argumentos posicionales opcionales?
Tengo un script que debe usarse así:
usage: installer.py dir [-h] [-v]
dir
es un argumento posicional que se define así:
parser.add_argument('dir', default=os.getcwd())
Quiero que dir
sea opcional: cuando no esté especificado, debería ser simplemente cwd
.
Desafortunadamente, cuando no especifico el dir
argumento, aparece Error: Too few arguments
.
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
Como una extensión de la respuesta de @VinaySajip. Hay otros nargs
que vale la pena mencionar .
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
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.
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.
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 nargs
no 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.
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 Path
tipo 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 -h
y -v
en 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. -h
es 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 -v
entonces,
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.version
vs 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