135 votes

Comment implémenter l'option --verbose ou -v dans un script ?

Je sais que le --verbose ou -v de plusieurs outils et j'aimerais l'intégrer à certains de mes propres scripts et outils.

J'ai pensé à placer :

if verbose:
    print ...

par le biais de mon code source, de sorte que si un utilisateur passe l'option -v la variable verbose sera réglé sur True et le texte sera imprimé.

Est-ce la bonne approche ou existe-t-il une méthode plus courante ?

Ajout : Je ne demande pas un moyen d'implémenter le parsing des arguments. Je sais comment cela est fait. Je suis seulement spécialement intéressé par l'option verbose.

11 votes

Pourquoi ne pas utiliser le module de journalisation et définir le niveau de journalisation INFO par défaut, et DEBUG lorsque --verbose est passé ? Il vaut mieux ne pas réimplémenter quelque chose qui est déjà disponible dans le langage...

3 votes

@Tim, je suis d'accord, mais le module de journalisation est assez pénible.

139voto

kindall Points 60645

Ma suggestion est d'utiliser une fonction. Mais plutôt que de mettre le if dans la fonction, ce que vous pourriez être tenté de faire, faites-le comme ceci :

if verbose:
    def verboseprint(*args):
        # Print each argument separately so caller doesn't need to
        # stuff everything to be printed into a single string
        for arg in args:
           print arg,
        print
else:   
    verboseprint = lambda *a: None      # do-nothing function

(Oui, vous pouvez définir une fonction dans un fichier if et elle ne sera définie que si la condition est vraie !)

Si vous utilisez Python 3, où print est déjà une fonction (ou si vous êtes prêt à utiliser la fonction print comme une fonction dans 2.x en utilisant from __future__ import print_function ), c'est encore plus simple :

verboseprint = print if verbose else lambda *a, **k: None

De cette façon, la fonction est définie comme une fonction qui ne fait rien si le mode verbeux est désactivé (en utilisant une lambda), au lieu de tester constamment la fonction verbose drapeau.

Si l'utilisateur pouvait changer le mode de verbosité pendant l'exécution de votre programme, ce serait la mauvaise approche (vous auriez besoin de la if dans la fonction), mais comme vous le définissez avec un drapeau de ligne de commande, vous ne devez prendre la décision qu'une seule fois.

Vous utilisez alors par exemple verboseprint("look at all my verbosity!", object(), 3) lorsque vous souhaitez imprimer un message "verbeux".

1 votes

Encore mieux, faites-le en tant que print fonction : Accepte de nombreux arguments. Elle peut être implémentée comme print(*args) en 3.x et comme for arg in args: print arg, en 2.x. Le principal avantage est qu'il permet de mélanger des chaînes de caractères et des éléments d'autres types dans un même message, sans qu'il soit nécessaire d'utiliser explicitement la fonction str appels/formatage et concaténations.

0 votes

A quoi sert la virgule à la fin de l'article ? print arg, ligne ?

0 votes

Il est facile de le déterminer par soi-même en expérimentant ou en consultant la documentation, mais il supprime le saut de ligne qui serait normalement imprimé.

79voto

Profpatsch Points 616

Utilisez le logging module :

import logging as log
…
args = p.parse_args()
if args.verbose:
    log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
    log.info("Verbose output.")
else:
    log.basicConfig(format="%(levelname)s: %(message)s")

log.info("This should be verbose.")
log.warning("This is a warning.")
log.error("This is an error.")

Tous ces éléments vont automatiquement à stderr :

% python myprogram.py
WARNING: This is a warning.
ERROR: This is an error.

% python myprogram.py -v
INFO: Verbose output.
INFO: This should be verbose.
WARNING: This is a warning.
ERROR: This is an error.

Pour plus d'informations, voir le Docs Python et le tutoriels .

12 votes

D'après les documents Python ici Dans le cas où vous avez besoin d'imprimer la sortie dans l'exécution normale du programme, la journalisation ne doit pas être utilisée. Il semble que c'est ce que le PO veut.

2 votes

Cela semble correct pour le problème de base, mais de nombreuses commandes *nix supportent également de multiples niveaux de verbosité (-v -v -v, etc.), ce qui peut devenir désordonné de cette façon.

1 votes

Je pense que votre premier exemple de code est manquant import argparse , p = argparse.ArgumentParser() y parser.add_argument('--verbose', '-v', action='count', default=0) ? Je suppose que l'ellipse indique qu'il y a du travail à faire, mais ce n'est pas évident pour ceux qui ne sont pas au courant. Peut-être qu'un lien vers une référence ferait l'affaire ?

19voto

mlissner Points 2158

En construisant et en simplifiant la réponse de @kindall, voici ce que j'utilise généralement :

v_print = None
def main()
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', '--verbosity', action="count", 
                        help="increase output verbosity (e.g., -vv is more than -v)")

    args = parser.parse_args()

    if args.verbosity:
        def _v_print(*verb_args):
            if verb_args[0] > (3 - args.verbosity):
                print verb_args[1]  
    else:
        _v_print = lambda *a: None  # do-nothing function

    global v_print
    v_print = _v_print

if __name__ == '__main__':
    main()

Cela fournit ensuite l'utilisation suivante tout au long de votre script :

v_print(1, "INFO message")
v_print(2, "WARN message")
v_print(3, "ERROR message")

Et votre script peut être appelé comme ceci :

% python verbose-tester.py -v
ERROR message

% python verbose=tester.py -vv
WARN message
ERROR message

% python verbose-tester.py -vvv
INFO message
WARN message
ERROR message

Quelques notes :

  1. Le premier argument est le niveau d'erreur, et le second est le message. Il a le nombre magique de 3 qui fixe la limite supérieure de votre journalisation, mais je l'accepte comme un compromis pour la simplicité.
  2. Si vous voulez v_print pour fonctionner dans tout votre programme, vous devez faire les cochonneries avec le global. Ce n'est pas drôle, mais je mets au défi quelqu'un de trouver un meilleur moyen.

1 votes

Pourquoi n'utilisez-vous pas le module de journalisation pour INFO et WARN ? C'est-à-dire l'importer lorsque -v est utilisé. Dans votre solution actuelle, tout est envoyé vers stdout au lieu de stderr. Et : vous voulez normalement relayer chaque erreur à l'utilisateur, n'est-ce pas ?

2 votes

Oui, c'est un bon point. La journalisation a une certaine surcharge cognitive que j'essayais d'éviter, mais c'est probablement la "bonne" chose à faire. Cela m'a juste ennuyé dans le passé...

9voto

jonesy Points 2176

Dans mes scripts, je vérifie au moment de l'exécution si l'option "verbose" est activée, puis je règle le niveau de journalisation sur "debug". Si l'option n'est pas activée, je la règle sur info. De cette façon, vous n'avez pas de vérifications "if verbose" partout dans votre code.

4voto

Lee-Man Points 320

Il pourrait être plus propre si vous avez une fonction, disons appelée vprint qui vérifie le drapeau verbeux pour vous. Ensuite, vous appelez simplement votre propre vprint à tout endroit où vous souhaitez une verbosité optionnelle.

2 votes

Cette solution est vraiment simple et élégante. merci !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X