Vous êtes ici : Accueil / Forums & ML / Forums Python / Forum général Python / Code conditionné par les flags

Code conditionné par les flags

Remonter à Forum général Python

Code conditionné par les flags

Envoyé par emmanuel_dumas le 28 Octobre 2014 à 11:48

Bonjour

 

Quand je codais en C, il m'arrivait souvent d'écrire cela :

#define MORE_DEBUG 1
...
if (MORE_DEBUG)
{
...
}
...
if (MORE_DEBUG)
{
...
}

 

Avantage : en modifiant en un seul endroit (ligne du #define), je modifiais le comportement de mon programme en plusieurs point. Note : quand le MORE_DEBUG est à 0, les sections de code sont simplement supprimé du code compilé final.

 

En python, j'essaye de trouver des stratégie équivalante.

J'ai d 'abord essayer les sections de code conditionnée par if 0 : ou if 1 :

exemple :

def foo1(a,b):
    if 0: c = a
    if a==1: c = b
    
    return c

je vérifie le résultat comme ceci :

import dis
dis.dis(foo1)

Qui renvoie

 38           0 LOAD_FAST                0 (a)
              3 LOAD_CONST               1 (1)
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_FALSE       21
             12 LOAD_FAST                1 (b)
             15 STORE_FAST               2 (c)
             18 JUMP_FORWARD             0 (to 21)

 40     >>   21 LOAD_FAST                2 (c)
             24 RETURN_VALUE

On constate que le « c=a » a tout simplement été supprimé, sans aucun « COMPARE_OP ». C'est le résultat que j'attend.

 

 

Je continu mes essais :

_flag0__ = 0

__flag1__ = 1

def foo2(a,b):
    a=b
    if __flag0__: a += 1
    if __flag1__: a += 2
    
    return a

 

je vérifie le résultat :

dis.dis(foo2)

qui renvoie :

 49           0 LOAD_FAST                1 (b)
              3 STORE_FAST               0 (a)

 50           6 LOAD_GLOBAL              0 (__flag0__)
              9 POP_JUMP_IF_FALSE       25
             12 LOAD_FAST                0 (a)
             15 LOAD_CONST               1 (1)
             18 INPLACE_ADD
             19 STORE_FAST               0 (a)
             22 JUMP_FORWARD             0 (to 25)

 51     >>   25 LOAD_GLOBAL              1 (__flag1__)
             28 POP_JUMP_IF_FALSE       44
             31 LOAD_FAST                0 (a)
             34 LOAD_CONST               2 (2)
             37 INPLACE_ADD
             38 STORE_FAST               0 (a)
             41 JUMP_FORWARD             0 (to 44)

 53     >>   44 LOAD_FAST                0 (a)
             47 RETURN_VALUE

 

Et la je vois des comparaisons avec les __flag0__ et __flag1__, ce n'est pas ce que j'attends.

 

Quelqu'un peu m'aider pour faire ce que je souhaite ?

 

Cordialement

Emmanuel

Re: Code conditionné par les flags

Envoyé par jacko le 29 Octobre 2014 à 13:47

Bonjour,

 

Ce que vous observez me semble tout à fait normal :

- En C, si vous écrivez "#define MORE_DEBUG 0", l'instruction "if (MORE_DEBUG)" est remplacée, après expansion, par "if (0)" -> le compilateur sait que le bloc ne sera jamais exécuté et, par souci d'optimisation, il le supprime (et encore, en êtes-vous bien certain ? ne confondez-vous pas avec "#if MORE_DEBUG" ?).

- En Python, dans votre exemple, comment pensez-vous que Python puisse prévoir quelle sera la valeur de __flag0__ lorsque foo2() sera exécutée ? Il n'en a bien sûr aucun moyen (__flag0__, initialisé à 0, peut être affecté à 1 de mille façons entre temps) -> il est donc tout à fait normal que le bloc "a+=1" soit conservé (au cas où __flag0__ vaudrait 1).

 

"pour faire ce que je souhaite ?" Que souhaitez-vous exactement ? S'il s'agit d'exécuter ou non un bloc en fonction d'une condition, le "if" marche très bien en Python comme en C, merci. S'il s'agit d'éliminer du code, il faut se souvenir que Python est un langage interprété (et éventuellement utilisé en session intéractive) : pas de pré-processing, et la compilation (en byte-code) n'est qu'une optimisation, ce n'est pas une étape fondamentale du processus comme dans un langage complié (le C). Essayez d'imaginer ce que pourrait signifier, dans une session intéractive, le fait de positionner une variable qui influe sur le byte-code généré pour un fonction, puis de modifier cette variable, d'appeler cette fonction, etc... cela n'aurait aucun sens.

Re: Code conditionné par les flags

Envoyé par emmanuel_dumas le 30 Octobre 2014 à 08:15

Bonjour

 

Je souhaite que dans ma release final de mon programme, il n'y ait que le code nécessaire, et que la machine virtuelle ne perde pas son temps à évaluer des conditions au résultat très prédictible.

 

Oui, lors de ma phase de développement, python interprète mon code. Mais dès la phase de développement fini, je "compile" mes fichiers .py en .pyc. Voici exactement la ligne qui fait cela aujourd'hui :

# Compile file
py_compile.compile( file=fileNamePy,
                    cfile=fileNamePyc,
                    dfile=fileNameHashGit )

 

Peut-on à un moment ou un autre dire "cette variable est une constante, donc faire les optimisations conséquentes" sur le code ?

 

Cordialement

Emmanuel

Re: Code conditionné par les flags

Envoyé par jacko le 30 Octobre 2014 à 16:20

Je ne pense pas que cela soit possible. Le compilateur Python, comme le compilateur C, ne peut évaluer et prendre de décisions que sur des constantes, jamais des variables. En C non plus, vous ne pouvez pas écrire :
int a ;
a=0 ;
puis "dire au compilateur" : "cette variable est une constante, donc faire les optimisations conséquentes". Ce que vous faites est possible seulement grâce au pré-processeur, qui permet de donner un nom MORE_DEBUG à la constante "0" ; mais cela reste toujours une constante pour le compilateur, après substitution.
Pour Python, langage interprété et intéractif, il n'y a pas de pré-processeur dans le processus normal d'utilisation.

Mais rien n'empêche de pré-processer soi-même le code source :

- Il existe (je pense) sur le Net des quantités de pré-processeurs de texte +/- généralistes. Et d'ailleurs, pourquoi ne pas utiliser le pré-processeur du C : s'il est bien fait, il doit pouvoir traiter des directives #define ou #if indépendamment du langage.
- Sinon, pourquoi ne pas écrire vous-même (en Python par ex.) un pré-processeur. Il peut être très simple et remplira exactement vos besoins. Par ex., les directives peuvent se présenter sous la forme de mots clefs dans les commentaires, on peut traiter facilement le fichier source par des regexp, etc. (par ex., j'utilise moi-même un tel pré-processeur pour générer du code compatible avec les version V2.x ou V3.x de Python à partir d'un seul fichier source ; les lignes de l'autre version sont simplement éliminées, comme dans votre besoin).

Dans tous les cas, c'est le résultat du pré-processing que vous fournissez à compile().

Rendu par Ploneboard