2010-01-05 2 views
9

mon code python est entrelacée avec beaucoup d'appels de fonction utilisés pour (débogage | profilage | traçage etc.) par exemple:python équivalent de « #define func() » ou comment commenter un appel de fonction en python

import logging 

logging.root.setLevel(logging.DEBUG) 
logging.debug('hello') 
j = 0 
for i in range(10): 
    j += i 
    logging.debug('i %d j %d' % (i,j)) 
print(j) 
logging.debug('bye') 

Je veux # définir ces fonctions consommatrices de ressources à partir du code. quelque chose comme l'équivalent c

#define logging.debug(val) 

oui, je sais que le mécanisme de niveau de journalisation du module d'enregistrement peut être utilisé pour masquer les mémorisations ci-dessous détaillent le niveau de journalisation. mais im demander d'une manière générale d'avoir les fonctions de saut d'interpréteur Python (qui prennent le temps de courir, même si elles ne faites pas beaucoup)

une idée est de redéfinir les fonctions que je veux commenter en fonctions vides:

def lazy(*args): pass 
logging.debug = lazy 

l'idée ci-dessus appelle encore une fonction, et peut créer une myriade d'autres problèmes

Répondre

17

Python ne possède pas de préprocesseur, bien que vous puissiez exécuter votre source python via un préprocesseur externe pour obtenir le même effet - par ex. sed "/logging.debug/d" supprimera toutes les commandes de journalisation du débogage. Ce n'est pas très élégant cependant - vous finirez par avoir besoin d'un système de construction pour exécuter tous vos modules via le préprocesseur et peut-être créer une nouvelle arborescence des fichiers .py traités avant d'exécuter le script principal.

Sinon, si vous mettez toutes vos instructions de débogage dans un bloc if __debug__:, elles seront optimisées lorsque python est exécuté avec l'indicateur -O (optimiser). En outre, j'ai vérifié le code avec le module de dis pour s'assurer qu'il a été optimisé.J'ai découvert que les deux

if __debug__: doStuff() 

et

if 0: doStuff() 

sont optimisés, mais

if False: doStuff() 

est pas. En effet, False est un objet Python régulier, et vous pouvez en effet faire:

>>> False = True 
>>> if False: print "Illogical, captain" 
Illogical, captain 

Ce qui me semble une faille dans la langue - je l'espère, il est fixé en Python 3.

Edit:

Ceci est corrigé dans Python 3: Attribution à Vrai ou Faux now gives a SyntaxError. Puisque Vrai et Faux sont constantes en Python 3, cela signifie que if False: doStuff() est maintenant optimisé:

>>> def f(): 
...  if False: print("illogical") 
... 
>>> dis.dis(f) 
    2   0 LOAD_CONST    0 (None) 
       3 RETURN_VALUE   
+0

Cela fonctionne de la même manière dans Python 3. – Brian

+0

préfixe si 0: | si __debug__: | si variable: + optimisation, que ce soit par un script ou un bon éditeur peut être la meilleure idée (mieux que le préfixe # qui ne gère pas les instructions multi-lignes).peut-être python n'est pas parfait après tout –

+1

@Dave: un joli virus python injecterait la ligne 'False, True = True, False' dans le code. des choses merveilleuses peuvent arriver –

0

Utilisez un module scope variable?

from config_module import debug_flag

et utiliser cette "variable" d'accès de porte à la fonction d'enregistrement (s). Vous construisez vous-même un module logging qui utilise le debug_flag pour ouvrir la fonctionnalité de journalisation.

+0

donc je dois ajouter un chèque avant chaque appel de fonction? –

+0

@random guy: Diriger que c'est déjà avec toutes ces déclarations de débogage ?? – cschol

+0

@jldupont: ne devrais-je pas changer tous les appels à la connexion à ma classe wrapper? –

0

Je pense qu'interdire totalement l'appel d'une fonction n'est pas possible, car Python fonctionne différemment de C. Le #define a lieu dans le pré-compilateur, avant que le code ne soit compilé. En Python, il n'y a pas de telle chose.

Si vous souhaitez supprimer complètement l'appel à déboguer dans un environnement de travail, je pense que le seul moyen de modifier réellement le code avant l'exécution. Avec un script précédent à l'exécution, vous pouvez commenter/décommenter les lignes de débogage.

Quelque chose comme ceci:

Fichier logging.py

#Main module 
def log(): 
    print 'logging' 

def main(): 
    log() 
    print 'Hello' 
    log() 

Fichier call_log.py

import re 
#To log or not to log, that's the question 
log = True 

#Change the loging 
with open('logging.py') as f: 
    new_data = [] 
    for line in f: 
     if not log and re.match(r'\s*log.*', line): 
     #Comment 
     line = '#' + line 
     if log and re.match(r'#\s*log.*', line): 
     #Uncomment 
     line = line[1:] 
     new_data.append(line) 

#Save file with adequate log level 
with open('logging.py', 'w') as f: 
    f.write(''.join(new_data)) 


#Call the module 
import logging 
logging.main() 

Bien sûr, il a ses problèmes, surtout s'il y a beaucoup de modules et sont complexes, mais pourraient être utilisables si vous devez absolument éviter l'appel à une fonction.

-1

Vous ne pouvez pas ignorer appels de fonction. Vous pourriez les redéfinir comme vides, par exemple. en créant un autre objet de journalisation qui fournit la même interface, mais avec des fonctions vides.

Mais de loin la plus propre approche est d'ignorer les messages du journal de faible priorité (comme vous le suggérez):

logging.root.setLevel(logging.CRITICAL) 
+1

Je n'ai pas été clair. Je suis à la recherche d'un piratage général python pour commenter les appels de fonction. c'est-à-dire que je veux que les fonctions 'commentées' ne soient même pas appelées. votre suggestion n'élimine pas l'appel de fonction à logging.debug(). la fonction est appelée et effectue un traitement. C'est ce que je veux éviter –

+0

Vous vous êtes fait comprendre, mais je ne pense pas qu'il soit pythonique de faire ce que vous avez demandé. – user238424

0

Avant de faire cela, avez-vous PROFILES pour vérifier que l'enregistrement prend en fait une quantité importante de temps? Vous pouvez constater que vous passez plus de temps à essayer de supprimer les appels que vous enregistrez.

Ensuite, avez-vous essayé quelque chose comme Psyco? Si vous avez des choses configurées pour que la journalisation soit désactivée, alors Psyco pourra peut-être optimiser la plus grande partie de la surcharge en appelant la fonction de journalisation, en remarquant qu'il retournera toujours sans action. Si vous trouvez que la journalisation prend un temps appréciable, vous pouvez alors envisager de surcharger la fonction de journalisation dans les boucles critiques, éventuellement en associant une variable locale à la fonction de journalisation ou à une fonction fictive, le cas échéant (ou en vérifiant None avant de l'appeler).

+0

Je ne me suis pas fait comprendre. J'ai utilisé le module de journalisation et la performance à titre d'exemple. Il existe d'autres raisons de vouloir commenter des fonctions, par exemple, lors de l'élimination d'une fonctionnalité du code –

1

Eh bien, vous pouvez toujours implémenter votre propre préprocesseur simple qui fait l'affaire. Ou, mieux encore, vous pouvez en utiliser un déjà existant. Say http://code.google.com/p/preprocess/

+0

Il existe également http://code.google.com/p/pypreprocessor/. –

2

Bien que je pense que la question est parfaitement claire et valide (malgré les nombreuses réponses qui suggèrent le contraire), la réponse courte est "il n'y a pas de support en Python pour cela".

La seule solution possible autre que le preprocessor suggestion serait d'utiliser quelques bytecode hacking. Je ne vais même pas commencer à imaginer comment cela devrait fonctionner en termes d'API de haut niveau, mais à un niveau bas, vous pourriez imaginer examiner des objets de code pour des séquences d'instructions particulières et les réécrire pour les éliminer.

Par exemple, regardez les deux fonctions suivantes:

>>> def func(): 
... if debug: # analogous to if __debug__: 
...  foo 
>>> dis.dis(func) 
    2   0 LOAD_GLOBAL    0 (debug) 
       3 JUMP_IF_FALSE   8 (to 14) 
       6 POP_TOP 

    3   7 LOAD_GLOBAL    1 (foo) 
      10 POP_TOP 
      11 JUMP_FORWARD    1 (to 15) 
     >> 14 POP_TOP 
     >> 15 LOAD_CONST    0 (None) 
      18 RETURN_VALUE 

Ici vous pouvez rechercher le LOAD_GLOBAL de debug, et l'éliminer et tout à la cible JUMP_IF_FALSE.

Celui-ci est plus fonction traditionnelle mise au point C de style() qui obtient bien oblitérée par un préprocesseur:

>>> def func2(): 
... debug('bar', baz) 
>>> dis.dis(func2) 
    2   0 LOAD_GLOBAL    0 (debug) 
       3 LOAD_CONST    1 ('bar') 
       6 LOAD_GLOBAL    1 (baz) 
       9 CALL_FUNCTION   2 
      12 POP_TOP 
      13 LOAD_CONST    0 (None) 
      16 RETURN_VALUE 

vous ici chercher LOAD_GLOBAL de debug et essuyer tout jusqu'au CALL_FUNCTION correspondant. Bien sûr, ces deux descriptions de ce que vous feriez sont bien plus simples que ce dont vous auriez vraiment besoin pour tous les modes d'utilisation sauf les plus simples, mais je pense que ce serait faisable. Faire un joli projet, si personne ne l'a déjà fait.

0

définir une fonction qui ne fait rien, ce

def nuzzing(*args, **kwargs): pass 

Ensuite, il suffit de surcharger toutes les fonctions que vous voulez vous débarrasser de votre fonction, ala

logging.debug = nuzzing 
+0

ma question d'origine inclut une variante de cette solution –

+0

Oui mais en laissant votre fonction d'espace réservé s'appeler récursivement, vous laissez la porte ouverte pour un mauvais fonctionnement immédiat (pile de profondeur d'appel max dépassée). Le compilateur cpython récent est assez intelligent pour réduire toute fonction qui n'est transmise à un noop, de sorte que tous les appels sont efficacement mis en commentaire. Je ne pense pas que vous allez trouver une meilleure solution. – richo

0

J'aime le « si __debug_ » solution sauf que le mettre en face de chaque appel est un peu distrayant et moche. J'ai eu le même problème et l'ai surmonté en écrivant un script qui analyse automatiquement vos fichiers sources et remplace les instructions de journalisation par des instructions pass (et des copies des instructions de journalisation commentées). Il peut également annuler cette conversion.

Je l'utilise lorsque je déploie un nouveau code dans un environnement de production lorsqu'il existe de nombreuses instructions de journalisation dont je n'ai pas besoin dans un environnement de production et qui affectent les performances.

Vous pouvez trouver le script ici: http://dound.com/2010/02/python-logging-performance/

Questions connexes