Programmation dans C
J'avais l'habitude d'avoir des sections de code uniquement utilisées à des fins de débogage (commandes de journalisation et autres). Ces instructions peuvent être complètement désactivées pour la production en utilisant #ifdef
directives de pré-processeur, comme ceci:
#ifdef MACRO
controlled text
#endif /* MACRO */
Quelle est la meilleure façon de faire quelque chose de similaire dans python
?
Si vous souhaitez simplement désactiver les méthodes de journalisation, utilisez le module logging
. Si le niveau de journalisation est défini pour exclure, par exemple, les instructions de débogage, alors logging.debug
sera très proche d'un no-op (il vérifie simplement le niveau de journal et retourne sans interpoler la chaîne de journal).
Si vous voulez réellement supprimer des morceaux de code au moment de la compilation du bytecode conditionnel à une variable particulière, votre seule option est le plutôt énigmatique __debug__
variable globale. Cette variable est définie sur True
sauf si -O
L'indicateur est passé à Python (ou PYTHONOPTIMIZE
est défini sur quelque chose de non vide dans l'environnement).
Si __debug__
est utilisé dans une instruction if
, l'instruction if
est en fait compilée uniquement dans la branche True
. Cette optimisation particulière est aussi proche d'une macro de préprocesseur que Python obtient jamais.
Notez que, contrairement aux macros, votre code doit toujours être syntaxiquement correct dans les deux branches de if
.
Pour montrer comment __debug__
fonctionne, considérez ces deux fonctions:
def f():
if __debug__: return 3
else: return 4
def g():
if True: return 3
else: return 4
Maintenant, vérifiez-les 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é".
Voici un exemple que j'utilise pour faire la distinction entre Python 2 & 3 pour mes Python programmes Tk:
import sys if sys.version_info [0] == 3: from tkinter import * from tkinter import ttk else: de Tkinter import * import ttk "" "reste de votre code" ""
J'espère que c'est une illustration utile.
Il est important de comprendre que dans Python def
et class
sont deux instructions 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 le préprocesseur en C et C++, vous pouvez utiliser le langage normal Python.
Le langage Python est fondamentalement différent du C et du C++ sur ce point car il n'existe aucun concept de "temps de compilation" et les deux seules phases sont le "temps d'analyse" (lorsque le code source est lu) et le "temps d'exécution" lorsque le code analysé (normalement composé principalement d'instructions de définition mais qui est en effet arbitraire Python) est exécuté.
J'utilise le terme "temps d'analyse" même si techniquement, lorsque le code source est lu dans la transformation, c'est une compilation complète en bytecode parce que la sémantique de la compilation C et C++ est différente et par exemple la définition d'une fonction se produit pendant cette phase ( tandis qu'à la place cela se produit lors de l'exécution en Python).
Même l'équivalent de #include
de C et C++ (qui dans 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 (analyse) afin qu'elle puisse être placée à l'intérieur d'un python if
. Tout à fait courant est par exemple d'avoir un import
à l'intérieur d'un bloc try
qui fournira des définitions alternatives pour certaines fonctions si une bibliothèque facultative Python n'est pas présente sur le système.
Enfin, notez que dans Python vous pouvez même créer de nouvelles fonctions et classes à l'exécution à partir de zéro en utilisant exec
, sans les avoir nécessairement dans votre code source. Vous pouvez également assembler ces objets utilisant directement du code parce que les classes et les fonctions ne sont en fait que des objets normaux (ceci n'est normalement fait que pour les classes).
Il existe certains outils qui essaient plutôt de considérer les définitions def
et class
et les instructions import
comme "statiques", par exemple pour effectuer une analyse statique de Python code pour générer des avertissements sur les fragments suspects ou pour créer un package déployable autonome qui ne dépend pas d'avoir une installation spécifique Python sur le système pour exécuter le programme. cependant, ils doivent pouvoir considérer que Python est plus dynamique que C ou C++ dans ce domaine et ils permettent également d'ajouter des exceptions pour les cas où l'analyse automatique échouera.
Pour autant que je sache, vous devez utiliser de véritables instructions if
. Il n'y a pas de préprocesseur, il n'y a donc pas d'analogue aux directives de préprocesseur.
Edit: En fait, il semble que la première réponse à cette question sera plus éclairante: Comment feriez-vous l'équivalent des directives de préprocesseur en Python?
Soi-disant, il existe une variable spéciale __debug__
qui, lorsqu'il est utilisé avec une instruction if
, sera évalué une fois, puis non évalué à nouveau lors de l'exécution.
Il n'y a pas d'équivalent direct à ma connaissance, vous pouvez donc vouloir effectuer un zoom arrière et reconsidérer les problèmes que vous avez utilisés pour résoudre à l'aide du préprocesseur.
Si ce n'est que la journalisation de diagnostic que vous recherchez, il existe un module de journalisation complet qui devrait couvrir tout ce que vous vouliez et plus encore.
http://docs.python.org/library/logging.html
Pour quoi d'autre utilisez-vous le préprocesseur? Configurations de test? Il y a un module de configuration pour ça.
http://docs.python.org/library/configparser.html
Rien d'autre?
Si vous utilisez #ifdef
pour vérifier les variables qui peuvent avoir été définies dans la portée au-dessus du fichier actuel, vous pouvez utiliser des exceptions. Par exemple, j'ai des scripts que je veux exécuter différemment de l'intérieur de ipython
par rapport à l'extérieur ipython
(afficher les tracés vs enregistrer les tracés, par exemple). J'ajoute donc
ipy = False
try:
ipy = __IPYTHON__
except NameError:
pass
Cela me laisse une variable ipy
, qui me dit si oui ou non __IPYTHON__
a été déclaré dans une étendue au-dessus de mon script actuel. C'est le parallèle le plus proche que je connaisse pour un #ifdef
fonction en Python.
Pour ipython
, c'est une excellente solution. Vous pouvez utiliser des constructions similaires dans d'autres contextes, dans lesquels un script appelant définit des valeurs variables et les scripts internes vérifient en conséquence. Bien entendu, cela dépendra de votre cas d'utilisation spécifique.
Si vous travaillez sur Spyder, vous n'avez probablement besoin que de ceci:
try:
print(x)
except:
#code to run under ifndef
x = "x is defined now!"
#other code
La première fois que vous exécutez votre script, vous exécuterez le code sous #code to run under ifndef
, le second, vous allez le sauter. Esperons que ça marche:)
Je ne l'ai pas essayé moi-même mais que diriez-vous https://code.google.com/p/pypreprocessor/
Ceci peut être réalisé en passant l'argument de ligne de commande comme ci-dessous:
import sys
my_macro = 0
if(len(sys.argv) > 1):
for x in sys.argv:
if(x == "MACRO"):
my_macro = 1
if (my_macro == 1):
controlled text
Essayez d'exécuter le script suivant et observez les résultats après cela:
python myscript.py MACRO
J'espère que cela t'aides.