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!
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".
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 .
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.
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:
- 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é. - 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.
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.
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
.
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.
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
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.