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

je connais le --verbose ou -v de plusieurs outils et j'aimerais l'implémenter dans certains de mes propres scripts et outils.

j'ai pensé à placeing

if verbose:
    print ...

à travers mon code source, de sorte que si un utilisateur passe l'option -v , la variable verbose sera définie à True et le texte sera imprimé.

est-ce la bonne approche ou y a-t-il une voie plus commune?

Plus: je ne demande pas une façon de mettre en œuvre l'analyse des arguments. Que je sais comment il est fait. Je ne m'intéresse qu'à l'option verbeuse. Merci!

65
demandé sur Qantas 94 Heavy 2011-05-12 19:01:39

9 réponses

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 une instruction 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 print comme une fonction dans 2.x à l'aide de 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 un do-nothing si le mode verbose est éteint (en utilisant un lambda), au lieu de tester constamment le drapeau verbose .

si l'utilisateur pouvait changer le mode de verbosité pendant l'exécution de votre programme, ce serait la mauvaise approche (vous auriez besoin du if dans la fonction), mais puisque vous le paramétrez avec un drapeau de ligne de commande, vous seulement besoin de prendre une décision une fois.

vous utilisez alors par exemple verboseprint("look at all my verbosity!", object(), 3) chaque fois que vous voulez imprimer un message" verbose".

83
répondu kindall 2011-05-12 16:35:13

utiliser 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 ceux-ci 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 les Python Docs et les tutoriels .

47
répondu Profpatsch 2013-03-14 15:04:53

ce que je fais dans mes scripts est de vérifier à l'exécution si l'option 'verbose' est activée, puis de définir mon niveau de journalisation au débogage. Si ce n'est pas réglé, je l'ai réglé sur info. De cette façon, vous n'avez pas "si verbeux" vérifie tout votre code.

9
répondu jonesy 2011-05-12 15:12:22

construire et simplifier la réponse de @kindall, voici ce que j'utilise habituellement:

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()

ceci fournit alors l'usage suivant dans tout 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. votre premier argument est votre niveau d'erreur, et le second est votre message. Il a le numéro magique de 3 qui définit la limite supérieure pour votre journalisation, mais je l'accepte comme un compromis pour la simplicité.
  2. si vous voulez que v_print fonctionne tout au long de votre programme, vous devez faire la camelote avec le global. Ce n'est pas drôle, mais je mets quelqu'un au défi de trouver un meilleur moyen.
8
répondu mlissner 2013-02-08 01:08:25

il pourrait être plus propre si vous avez une fonction, dites vprint , qui vérifie le drapeau verbeux pour vous. Ensuite, vous appelez juste votre propre vprint fonction tout endroit où vous voulez verbosité facultative.

2
répondu Lee-Man 2011-05-12 15:06:27

j'ai volé le code d'enregistrement à partir de virtualenv pour un projet de mine. Regardez dans main() de virtualenv.py pour voir comment il est initialisé. le code est parsemé de logger.notify() , logger.info() , logger.warn() , et ainsi de suite. Les méthodes qui émettent réellement des sorties sont déterminées par si virtualenv a été invoqué avec -v , -vv , -vvv , ou -q .

2
répondu George V. Reilly 2016-06-08 20:51:35

J'ai besoin d'une fonction qui imprime un objet (obj), mais seulement si la variable globale verbose est vraie, sinon elle ne fait rien.

je veux pouvoir changer le paramètre global" verbose " à tout moment. La simplicité et la lisibilité sont pour moi d'une importance capitale. Donc je procéderais comme les lignes suivantes indiquent:

ak@HP2000:~$ python3
Python 3.4.3 (default, Oct 14 2015, 20:28:29) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> verbose = True
>>> def vprint(obj):
...     if verbose:
...         print(obj)
...     return
... 
>>> vprint('Norm and I')
Norm and I
>>> verbose = False
>>> vprint('I and Norm')
>>> 

la variable globale "verbose" peut aussi être définie à partir de la liste des paramètres.

0
répondu user377367 2015-12-29 01:18:21

la solution de @kindall ne fonctionne pas avec ma version Python 3.5. @styles indique correctement dans son commentaire que la raison est l'argument optionnel supplémentaire mots clés . Par conséquent, ma version légèrement améliorée pour Python 3 ressemble à ceci:

if VERBOSE:
    def verboseprint(*args, **kwargs):
        print(*args, **kwargs)
else:
    verboseprint = lambda *a, **k: None # do-nothing function
0
répondu stefanct 2017-05-23 12:25:39

il pourrait y avoir une variable globale, probablement définie avec argparse de sys.argv , qui indique si le programme devrait être verbeux ou non. Alors un décorateur pourrait être écrit de telle sorte que si verbosity était sur, alors l'entrée standard serait détourné dans le dispositif null tant que la fonction serait d'exécuter:

import os
from contextlib import redirect_stdout
verbose = False

def louder(f):
    def loud_f(*args, **kwargs):
        if not verbose:
            with open(os.devnull, 'w') as void:
                with redirect_stdout(void):
                    return f(*args, **kwargs)
        return f(*args, **kwargs)
    return loud_f

@louder
def foo(s):
    print(s*3)

foo("bar")

cette réponse est inspirée de ce code ; en fait, j'allais juste l'utiliser comme un module dans mon programme, mais J'ai eu des erreurs que je ne comprenais pas, alors j'en ai adapté une partie.

l'inconvénient de cette solution est que la verbosité est binaire, contrairement à logging , qui permet de mieux ajuster la façon dont verbose le programme peut être. En outre, tous print les appels sont détournés, ce qui pourrait être indésirable pour.

0
répondu Daniel Diniz 2018-06-04 11:55:55