Comment implémenter "#ifdef " en python?

programmation dans C j'avais l'habitude d'avoir des sections de code utilisées uniquement pour le débogage (commandes de journalisation et similaires). Ces instructions pourraient être complètement désactivées pour la production en utilisant les directives #ifdef pré-processeur, comme ceci:

 #ifdef MACRO

 controlled text

 #endif /* MACRO */

Quelle est la meilleure façon de faire quelque chose de similaire dans python ?

26
demandé sur qrdl 2012-09-21 09:08:08

7 réponses

si vous voulez juste désactiver les méthodes de journalisation, utilisez le module logging . Si le niveau de log est défini pour exclure, disons, les instructions de débogage, alors logging.debug sera très proche d'un no-op (il vérifie simplement le niveau de log et retourne sans interpoler la chaîne de log).

si vous voulez réellement supprimer des morceaux de code au moment de la compilation de bytecode conditionnée à une variable particulière, votre seule option est la variable globale __debug__ plutôt énigmatique. Ce la variable est définie à True sauf si le drapeau -O est passé à Python (ou PYTHONOPTIMIZE est défini à quelque chose de non vide dans l'environnement).

si __debug__ est utilisé dans une déclaration if , la déclaration if est en fait compilée dans la seule branche True . Cette optimisation particulière est aussi proche d'une macro préprocesseur que Python ne l'obtient jamais.

Notez que, contrairement aux macros, votre code doit toujours être syntaxiquement correct dans les deux branches du if .


pour montrer comment __debug__ fonctionne, considérer ces deux fonctions:

def f():
    if __debug__: return 3
    else: return 4

def g():
    if True: return 3
    else: return 4

vérifiez maintenant avec dis :

>>> dis.dis(f)
  2           0 LOAD_CONST               1 (3)
              3 RETURN_VALUE        
>>> dis.dis(g)
  2           0 LOAD_GLOBAL              0 (True)
              3 JUMP_IF_FALSE            5 (to 11)
              6 POP_TOP             
              7 LOAD_CONST               1 (3)
             10 RETURN_VALUE        
        >>   11 POP_TOP             

  3          12 LOAD_CONST               2 (4)
             15 RETURN_VALUE        
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

comme vous pouvez le voir, seul f est"optimisé".

22
répondu nneonneo 2012-09-21 05:51:17

il est important de comprendre que dans Python def et class sont deux déclarations exécutables régulières...

import os

if os.name == "posix":
    def foo(x):
        return x * x
else:
    def foo(x):
        return x + 42
...

donc pour faire ce que vous faites avec préprocesseur en C et C++, vous pouvez utiliser le régulier langage Python.

le langage Python est fondamentalement différent de C et C++ sur ce point parce qu'il n'existe pas de concept de "temps de compilation" et que les deux seules phases sont "Temps d'analyse" (lorsque le code source est lu en) et "run time" quand le code parsé (normalement composé principalement d'instructions de définition mais qui est en fait du code Python arbitraire) est exécuté.

j'utilise le terme" parse time " même si techniquement quand le code source est lu dans la transformation est une compilation complète en bytecode parce que la sémantique de C et c++ compilation est différente et par exemple la définition d'une fonction se produit pendant cette phase (alors qu'à la place il se produit à l'exécution en Python).

même l'équivalent de #include de C et C++ (qui en Python est import ) est une instruction régulière qui est exécutée au moment de l'exécution et non au moment de la compilation (parse) de sorte qu'elle peut être placée dans un python régulier if . Très commun est par exemple d'avoir un import dans un bloc try qui fournira des définitions alternatives pour certaines fonctions si une bibliothèque optionnelle Python spécifique n'est pas présente sur le système.

Enfin, notez qu'en Python vous pouvez même créer de nouvelles fonctions et classes à partir de zéro en utilisant exec , sans les avoir nécessairement dans votre code source. Vous pouvez aussi assembler ces objets directement en utilisant le code parce que les classes et les fonctions sont en effet juste des objets réguliers (ce qui est normalement fait seulement pour les classes, cependant).

il y a certains outils qui essaient plutôt de considérer def et class définitions et import déclarations comme "statique", par exemple pour faire une analyse statique du code Python pour générer des avertissements sur des fragments suspects ou pour créer un paquet déployable autonome qui ne dépend pas d'avoir une installation Python spécifique sur le système pour exécuter le programme. Tous doivent cependant être en mesure de considérer que Python est plus dynamique que C ou C++ dans ce domaine et ils permettent aussi d'ajouter des exceptions pour l'emplacement de l'analyse automatique échoue.

6
répondu 6502 2015-05-09 19:05:11

autant que je sache, vous devez utiliser les déclarations actuelles if . Il n'y a pas de préprocesseur, donc il n'y a pas d'équivalent aux directives préprocesseur.

Edit: en fait, il semble que la réponse à cette question sera plus éclairante: comment feriez-vous l'équivalent des directives préprocesseur en Python?

il y aurait une variable spéciale __debug__ qui, lorsqu'elle est utilisée avec un if déclaration, sera évalué une fois et puis ne sera pas évalué à nouveau pendant l'exécution.

5
répondu Andrew Gorcester 2017-05-23 10:30:43

voici un exemple que j'utilise pour distinguer entre Python 2 et 3 pour mes programmes Python Tk:


import sys
if sys.version_info[0] == 3:
    from tkinter import *
    from tkinter import ttk
else:
    from Tkinter import *
    import ttk

""" rest of your code """

l'Espérance qui est une illustration utile.

3
répondu Richard 2016-04-06 21:23:59

il n'y a pas d'équivalent direct que je connaisse, donc vous pourriez vouloir zoomer et reconsidérer les problèmes que vous avez utilisé pour résoudre en utilisant le préprocesseur.

S'il ne s'agit que de journalisation diagnostique, vous êtes après alors il ya un module de journalisation complète qui devrait couvrir tout ce que vous vouliez et plus.

http://docs.python.org/library/logging.html

quoi d'autre utilisez-vous le préprocesseur pour? Configurations d'essai? Il y a un module de configuration pour ça.

http://docs.python.org/library/configparser.html

autre chose?

1
répondu John Mee 2012-09-21 05:25:44

si vous utilisez #ifdef pour vérifier les variables qui peuvent avoir été définies dans la portée au-dessus du fichier courant, vous pouvez utiliser des exceptions. Par exemple, j'ai des scripts que je veux exécuter différemment de dans ipython vs à l'extérieur ipython (Afficher des tracés vs enregistrer des tracés, par exemple). Donc j'ajoute

     ipy = False
     try:
        ipy = __IPYTHON__
     except NameError:
        pass

cela me laisse avec une variable ipy , qui me dit si oui ou non __IPYTHON__ a été déclaré dans une portée au-dessus de mon script actuel. C'est le parallèle le plus proche que je connaisse pour une fonction #ifdef en Python.

Pour ipython , c'est une excellente solution. Vous pouvez utiliser des constructions similaires dans d'autres contextes, dans lesquels un script appelant fixe des valeurs variables et les scripts internes vérifient en conséquence. La question de savoir si cela a un sens ou non dépend évidemment de votre cas d'utilisation spécifique.

0
répondu mmdanziger 2015-06-07 11:48:43

Je ne l'ai pas essayé moi-même mais pourquoi pas https://code.google.com/p/pypreprocessor/

0
répondu Mark Lawrence 2015-06-28 02:02:41