Comprobando si sys.argv [x] está definido

Respuestas:

64

Al final, la diferencia entre try, excepty probar len(sys.argv)no es tan significativa. Ambos son un poco pirateados en comparación con argparse.

Sin embargo, esto se me ocurre, como una especie de argumentación de bajo presupuesto:

arg_names = ['command', 'x', 'y', 'operation', 'option']
args = dict(zip(arg_names, sys.argv))

Incluso podría usarlo para generar namedtuplevalores con valores predeterminados None, ¡todo en cuatro líneas!

Arg_list = collections.namedtuple('Arg_list', arg_names)
args = Arg_list(*(args.get(arg, None) for arg in arg_names))

En caso de que no esté familiarizado namedtuple, es solo una tupla que actúa como un objeto, lo que le permite acceder a sus valores usando tup.attributesintaxis en lugar de tup[0]sintaxis.

Entonces, la primera línea crea un nuevo namedtupletipo con valores para cada uno de los valores en arg_names. La segunda línea pasa los valores del argsdiccionario, usando getpara devolver un valor predeterminado cuando el nombre del argumento dado no tiene un valor asociado en el diccionario.

remitente
fuente
¡Amo Python cada vez más, todo gracias a respuestas como esa y Stack Overflow, por supuesto! Lástima que no tengamos una explicación de las dos últimas líneas. Creo que para los principiantes sería genial.
Goujon
2
¡Quiéralo! Fácilmente la mejor solución que he visto para este problema. Para otros: No fue inmediatamente obvio para mí (newb) que: 1) el 'comando' pasará como el primer argumento cada vez y 2) puede llamar a los resultados con args [0], etc.
Matt D
Esto es genial, seguro, pero ¿qué tiene de malo probar la longitud?
colorlace
1
@timwiz Solo estaba hablando en comparación con el uso de argparse. Aún así, en estos días, me pateo cada vez que vuelvo a un guión antiguo y descubro que no usé argparse.
remitente
116

Verifique la longitud de sys.argv:

if len(sys.argv) > 1:
    blah = sys.argv[1]
else:
    blah = 'blah'

Algunas personas prefieren el enfoque basado en excepciones que ha sugerido (p. Ej., try: blah = sys.argv[1]; except IndexError: blah = 'blah'), Pero no me gusta tanto porque no se "escala" tan bien (p. Ej., Cuando desea aceptar dos o tres argumentos) y potencialmente puede ocultar errores (por ejemplo, si usó blah = foo(sys.argv[1]), pero foo(...)generó un IndexError, IndexErrorse ignoraría).

David Wolever
fuente
1
Sin embargo, mientras seas atómico al respecto, no hay nada de qué preocuparse try, except. Espere foosu argumento hasta la elsecláusula.
remitente
3
Además, una vez que esté pensando en escalar, es hora de pasar a argparse.
remitente
1
+1 en argparse. Tengo argparse.pyen todos mis proyectos de línea de comandos.
David Wolever
2
@senderle: claro, si eres diligente al respecto, está bien. Pero en mi experiencia, la mayoría de los programadores no son diligentes y ponen toda la lógica en la trycláusula ... Entonces, dado que no es más difícil (y, en mi opinión, un poco más bonito), prefiero simplemente verificar la longitud (también, evitas que la gente gritarle por usar excepciones para el control de flujo).
David Wolever
2
@David, sí, veo tu punto. Soy un poco tryapologista, debo admitir. Simplemente siento que a veces expresa mi intención con más claridad que una ifdeclaración.
remitente
22

Otra forma que aún no he visto en la lista es establecer su valor centinela antes de tiempo. Este método aprovecha la evaluación perezosa de Python, en la que no siempre es necesario proporcionar una elsedeclaración. Ejemplo:

startingpoint = 'blah'
if len(sys.argv) >= 2:
  startingpoint = sys.argv[1]

O si se está volviendo loco con la sintaxis, puede usar el operador ternario de Python :

startingpoint = sys.argv[1] if len(sys.argv) >= 2 else 'blah'
jatismo
fuente
1
La respuesta del operador ternario es a mis ojos la más bonita. Estoy sentado aquí maldiciendo en silencio el hecho de que parte del software que mantengo está vinculado a Python 2.4, que no lo tiene.
Richard Barrell
11

Yo uso esto, nunca falla:

startingpoint = 'blah'
if sys.argv[1:]:
   startingpoint = sys.argv[1]
anatoly techtonik
fuente
Eso no es para comprobar si está definido. Es más como definir si existe, que no es lo mismo. Yo también utilicé esa forma para evaluar las variables de respaldo, pero no es una respuesta a la pregunta actual.
m3nda
@ erm3nda Puedo eliminar la startingpointvariable del ejemplo, pero la pregunta es asignar una variable alternativa, así que hice lo mismo.
anatoly techtonik
1
Si lo quita, obtendrá un error sobre la variable no definida. He vuelto a leer la pregunta, y lo que él espera es que, un reemplazo de variable :) así que está bien. Gracias por el consejo de ese corto camino si sys.argv[1:]:. Esto funciona con argumentos posicionales mientras que count no lo hace.
m3nda
10

Es una lista de Python normal. La excepción que detectaría para esto es IndexError, pero es mejor que solo verifique la longitud.

if len(sys.argv) >= 2:
  startingpoint = sys.argv[1]
else:
  startingpoint = 'blah'
Richard Barrell
fuente
2

¡Una solución que funciona con función de mapa incorporada!

arg_names = ['command' ,'operation', 'parameter']
args = map(None, arg_names, sys.argv)
args = {k:v for (k,v) in args}

Entonces solo tienes que llamar a tus parámetros así:

if args['operation'] == "division":
    if not args['parameter']:
        ...
    if args['parameter'] == "euclidian":
        ...
Guillaume Hillion
fuente
1

Simplemente puede agregar el valor de argv [1] a argv y luego verificar si argv [1] no es igual a la cadena que ingresó. Ejemplo:

from sys import argv
argv.append('SomeString')
if argv[1]!="SomeString":
            print(argv[1])
Hassan Abdul-Kareem
fuente
para los que me votaron en contra, qué vergüenza, por no aclarar el error.
Hassan Abdul-Kareem
Supongo que es porque es hackish. ¿Qué pasa si alguien pasa SomeString como argumento? ¿Cómo usar eso si puede aceptar, digamos de 1 a 5 argumentos?
pbogut
Genial (pero aún hackish) para establecer un valor predeterminado en caso de que el usuario no proporcione el argumento. Simplemente agregue y luego use argv [1].
Felizett
1

Muy cerca de lo que el creador estaba tratando de hacer. Aquí hay una función que uso:

def get_arg(index):
    try:
        sys.argv[index]
    except IndexError:
        return ''
    else:
        return sys.argv[index]

Entonces, un uso sería algo como:

if __name__ == "__main__":
    banner(get_arg(1),get_arg(2))
J. Barber
fuente