Vérifier si sys.argv [x] est défini

Réponses:

64

En fin de compte, la différence entre les try, excepttests et les tests len(sys.argv)n'est pas si significative. Ils sont tous les deux un peu hackish par rapport àargparse .

Cela me vient à l'esprit - comme une sorte d'argument à petit budget:

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

Vous pouvez même l'utiliser pour générer un namedtupleavec des valeurs par défaut None- le tout sur quatre lignes!

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

Au cas où vous ne seriez pas familier avec namedtuple, c'est juste un tuple qui agit comme un objet, vous permettant d'accéder à ses valeurs en utilisant la tup.attributesyntaxe au lieu de la tup[0]syntaxe.

Ainsi, la première ligne crée un nouveau namedtupletype avec des valeurs pour chacune des valeurs dans arg_names. La deuxième ligne transmet les valeurs du argsdictionnaire, en utilisant getpour renvoyer une valeur par défaut lorsque le nom d'argument donné n'a pas de valeur associée dans le dictionnaire.

expéditeur
la source
J'adore de plus en plus Python, tout cela grâce à des réponses comme ça et bien sûr Stack Overflow! Dommage que nous n'ayons pas d'explication sur les deux dernières lignes. Je crois que ce serait génial pour les débutants.
Goujon
2
Aimer! Facilement la meilleure solution que j'ai vue de ce problème. Pour les autres: Il n'était pas immédiatement évident pour moi (newb) que: 1) la 'commande' passera à chaque fois comme premier argument et 2) vous pouvez appeler les résultats avec args [0] etc.
Matt D
C'est bien sûr, mais qu'est-ce qui est piraté dans le test de la longueur?
colorlace
1
@timwiz Je ne parlais que de l'utilisation d'argparse. Pourtant, ces jours-ci, je me donne des coups de pied chaque fois que je reviens à un ancien script et découvre que je n'ai pas utilisé argparse.
senderle le
116

Vérifiez la longueur de sys.argv:

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

Certaines personnes préfèrent l'approche basée sur les exceptions que vous avez suggérée (par exemple, try: blah = sys.argv[1]; except IndexError: blah = 'blah'), mais je ne l'aime pas autant car elle ne «s'adapte» pas aussi bien (par exemple, lorsque vous souhaitez accepter deux ou trois arguments) et il peut potentiellement masquer des erreurs (par exemple, si vous avez utilisé blah = foo(sys.argv[1]), mais foo(...)soulevé un IndexError, cela IndexErrorserait ignoré).

David Wolever
la source
1
Tant que vous êtes atomique à ce sujet, il n'y a rien à craindre try, except. Attendez simplement foovotre argument jusqu'à la elseclause.
senderle
3
De plus, une fois que vous pensez à la mise à l'échelle, il est temps de passer à argparse.
senderle
1
+1 sur argparse. J'ai argparse.pydans tous mes projets en ligne de commande.
David Wolever
2
@senderle: bien sûr, si vous êtes diligent à ce sujet, c'est très bien. Mais d'après mon expérience, la plupart des programmeurs ne sont pas diligents et mettent toute la logique dans la tryclause ... Donc, étant donné que ce n'est pas plus difficile (et, à mon avis , un peu plus joli), je préfère juste vérifier la longueur (aussi, vous évitez d'avoir des gens crier après avoir utilisé des exceptions pour le contrôle de flux).
David Wolever
2
@David, ouais, je comprends votre point de vue. Je suis un peu tryapologiste, je dois l'admettre. J'ai juste le sentiment que cela exprime parfois mon intention plus clairement qu'une ifdéclaration.
senderle
22

Une autre façon que je n'ai pas encore vue dans la liste est de définir votre valeur sentinelle à l'avance. Cette méthode tire parti de l'évaluation paresseuse de Python, dans laquelle vous n'avez pas toujours à fournir une elseinstruction. Exemple:

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

Ou si vous allez à la syntaxe CRAZY, vous pouvez utiliser l' opérateur ternaire de Python :

startingpoint = sys.argv[1] if len(sys.argv) >= 2 else 'blah'
jathanisme
la source
1
La réponse de l'opérateur ternaire est à mes yeux la plus jolie. Je suis assis ici à maudire tranquillement le fait que certains des logiciels que je maintiens sont liés à Python 2.4, qui ne l'a pas.
Richard Barrell
11

J'utilise ceci - cela n'échoue jamais:

startingpoint = 'blah'
if sys.argv[1:]:
   startingpoint = sys.argv[1]
anatoly techtonik
la source
Ce n'est pas à vérifier s'il est défini. Est plus comme définir si existe, ce qui n'est pas le même. J'ai également utilisé cette méthode pour définir des variables de repli, mais ce n'est pas une réponse à la question actuelle.
m3nda
@ erm3nda Je peux supprimer la startingpointvariable de l'exemple, mais la question est d'attribuer une variable de secours, donc j'ai juste fait la même chose.
anatoly techtonik
1
Si vous le supprimez, vous obtiendrez une erreur concernant la variable non définie. J'ai relu la question, et ce qu'il attend, c'est que, un remplacement de variable :) donc ça va. Merci pour les conseils de ce court chemin si sys.argv[1:]:. Cela fonctionne avec les arguments de position, contrairement à count.
m3nda
10

C'est une liste Python ordinaire. L'exception que vous attraperiez pour cela est IndexError, mais vous feriez mieux de simplement vérifier la longueur à la place.

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

Une solution fonctionnant avec la fonction intégrée de carte!

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

Ensuite, il vous suffit d'appeler vos paramètres comme ceci:

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

Vous pouvez simplement ajouter la valeur de argv [1] à argv puis vérifier si argv [1] n'est pas égal à la chaîne que vous avez entrée Exemple:

from sys import argv
argv.append('SomeString')
if argv[1]!="SomeString":
            print(argv[1])
Hassan Abdul-Kareem
la source
pour ceux qui m'ont voté à la baisse, honte à vous, de ne pas avoir clarifié l'erreur.
Hassan Abdul-Kareem le
Je suppose que c'est parce que c'est hackish. Et si quelqu'un passait SomeString comme argument? Comment l'utiliser si vous pouvez accepter disons 1 à 5 arguments?
pbogut
Cool (mais toujours hackish) pour définir une valeur par défaut au cas où l'utilisateur ne fournirait pas l'argument. Ajoutez simplement puis utilisez argv [1].
Felizett
1

Assez proche de ce que l'auteur essayait de faire. Voici une fonction que j'utilise:

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

Donc, une utilisation serait quelque chose comme:

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