Disons que j'ai un programme principal (test.py) et un petit programme utilitaire (test_utils.py) qui a des fonctions d'assistance appelées par le programme principal. Je voudrais activer les instructions de débogage dans le code en passant un debug_flag booléen, qui est lu via argparse.

Maintenant, j'aimerais que les fonctions de mon programme test_utils.py impriment également des instructions de débogage, en fonction de la valeur de debug_flag. Je pourrais toujours ajouter debug_flag en tant que paramètre à chaque définition de fonction dans test_utils.py et passer le paramètre lorsque la fonction est appelée, mais y a-t-il un meilleur moyen ici, comme faire de debug_flag une variable globale ? Mais si je déclare que debug_flag est global à partir de test.py, comment cela serait-il importé dans test_utils.py?

Quelle serait l'approche la plus élégante / Pythonique ici?

Test.py:

import argparse
from test_utils import summation

def main():
    args = get_args()
    debug_flag = True if args[debug] == 'True' else False
    print summation(5, 6, 7)

def get_args():
    parser = argparse.ArgumentParser(description='Test program')
    parser.add_argument('-d','--debug', help='Debug True/False', default=False)
    args = vars(parser.parse_args())
    return args

Test_utils.py:

from test import debug_flag

def summation(x, y, z):
    if debug_flag:
        print 'I am going to add %s %s and %s' % (x, y, z)
    return x + y + z

EDIT1: Pour clarifier - si je passe l'indicateur de débogage via argparse et que je définis ainsi debug_flag sur True - comment cela serait-il propagé aux fonctions dans test_utils.py?

EDIT2: Basé sur la suggestion de @ joran-beasley, voici ce que j'ai.

Test.py:

import argparse
import logging
from test_utils import summation

def main():
    args = get_args()
    logging.getLogger("my_logger").setLevel(logging.DEBUG if args['debug'] == 'True' else logging.WARNING)
    print summation(5, 6, 7)

def get_args():
    parser = argparse.ArgumentParser(description='Test program')
    parser.add_argument('-d','--debug', help='Debug True/False', required=True)
    args = vars(parser.parse_args())
    return args

main()

Test_utils.py

import logging

log = logging.getLogger('my_logger')

def summation(x, y, z):
    log.debug('I am going to add %s %s and %s' % (x, y, z))
    return x + y + z

Lorsque je lance test.py, j'obtiens:

$ python test.py -d True
No handlers could be found for logger "my_logger"
18
6
Craig 11 avril 2018 à 20:52

3 réponses

Meilleure réponse

Utiliser la journalisation

# this logger will always now be logging.DEBUG level
logging.getLogger("my_logger").setLevel(logging.DEBUG if args.debug else logging.WARNING)

Puis utilisez

log = logging.getLogger("my_logger")
...
log.warn("some text that should always be seen!")
log.debug("some debug info!")

Vous pouvez alors faire des choses où vous avez plusieurs niveaux de journalisation

log_level = logging.WARNING
if args.verbose > 0:
   log_level = logging.INFO
elif args.verbose > 3:
   log_level = logging.DEBUG

Si, pour une raison quelconque, vous aviez besoin de récupérer le niveau de journal effectif actuel (vous ne devriez vraiment pas dans la plupart des cas ... utilisez simplement log.debug lorsque vous voulez une sortie de niveau de débogage)

logging.getLogger("my_logger").getEffectiveLevel()

[modifier pour clarifier]

log = logging.getLogger('my_logger')

def summation(x, y, z):
   log.debug('I am going to add %s %s and %s' % (x, y, z)) # will not print if my_logger does not have an effective level of debug
   return x + y + z

print(summation(2, 3, 4))
log.setLevel(logging.DEBUG)
print(summation(4, 5, 6))

Ou vous pouvez écrire une fonction d'aide

def is_debug():
    return logging.getLogger("my_logger").getEffectiveLevel() == logging.DEBUG

Grossier, vous pouvez toujours faire des horribles conneries hacky, comme l'écrire dans un fichier plat et le lire ou utiliser des variables vraiment globales (plus difficile que vous ne le pensez et beaucoup de cas marginaux à craindre)

4
Joran Beasley 11 avril 2018 à 18:23

Réponse simple. Attribuez un dict dans le fichier principal. Importez-le ensuite via tous les autres modules.

Test.py

debug_flag = {'setting' : False}

Test_utils.py

from test import debug_flag

def print_flag():
    print(debug_flag['setting'])

def set_flag(setting):
    debug_flag['setting'] = setting

set_flag(True)
print_flag()

Maintenant, chaque fois que vous importez le debug_flag à partir du module principal, il aura également le paramètre que vous définissez le drapeau une fois que vous avez traité l'analyse d'argument. Vous pouvez ensuite modifier cela à tout moment, et les appels suivants prendront la modification.

0
eatmeimadanish 11 avril 2018 à 20:22

Vous pouvez obtenir un global "à l'échelle du package" en Python en passant un mutable. Mon approche préférée dans ces situations est de créer une classe Flags personnalisée. Vous partagez ensuite une instance de Flags entre tous vos modules, et ses attributs fonctionnent comme des globaux. Voici un exemple en termes de code que vous avez publié:

Test_utils.py

__all__ = ['flags', 'summation']

class Flags(object):
    def __init__(self, *items):
        for key,val in zip(items[:-1], items[1:]):
            setattr(self,key,val)

flags = Flags('debug', False)

def summation(x, y, z):
    if flags.debug:
        print 'I am going to add %s %s and %s' % (x, y, z)
    return x + y + z

Test.py

#!/usr/bin/env python2
import argparse
import sys

from test_utils import summation, flags

def main():
    args = get_args()
    flags.debug = args['debug']
    print summation(5, 6, 7)

def get_args():
    parser = argparse.ArgumentParser(description='Test program')
    parser.add_argument('-d','--debug', action='store_true', help='Debug True/False', default=False)
    args = vars(parser.parse_args())
    return args

if __name__=='__main__':
    main()

J'ai déplacé des drapeaux vers test_utils.py pour éviter un problème d'importation circulaire, mais cela ne devrait rien affecter. Une solution plus robuste (appropriée pour les projets plus importants) serait d'avoir un module config.py (ou quelque chose) séparé dans lequel flags est initialisé.

0
tel 11 avril 2018 à 18:26