:PROPERTIES:
:ID:       26e1fdfb-1f8e-4c62-a08f-468a56ab03c8
:mtime:    20220501153548
:ctime:    20220501130626
:END:
#+title: Peephole optimization

* Introduction
Lorsque du code python est exécuté, celui-ci est compilé en /bytecode/ et enregistré dans des fichiers .pyc stockés dans
les répertoires ~__pycache__~. Ces fichiers .pyc contiennent une version *optimisée* et plus *rapide* du code.

** L'objet /code/
L'objet compilé /code/:
 * Est accessible depuis l'attribut ~__code__~ des fonctions,
 * Contient le *bytecode* et d'autres informations nécessaires à *CPython* pour son exécution, notamment :
   * ~co_consts~ : un tuple regroupant les constantes présentes dans la fonction,
   * ~co_varnames~ : un tuple regroupant le nom des variables locales utilisées par la fonction,
   * ~co_names~ : un tuple regroupant les noms non-locaux référencés dans le corps de la fonction.

* L'optimisation /Peephole/
Durant la phase de *transcription* en bytecode, certaines données telles que les expressions numériques, /strings/ et /tuples/ sont optimisées et stockées dans des instruction *bytecode*. 

** Les expressions constantes
*** Les calculs numériques
Les *expressions constantes* telles que ~a = 30 * 8 * 70~ sont optimisées.
*** Les chaines de caractères et tuples
Les *strings* dont la *longueur <= 4096* et les *tuples* dont la *longueur <= 256* sont optimisées, les autres, non.
*** Les /membership tests/
Les *membership tests* (opérateur ~in~ et ~not in~) permettent de tester la présence d'une valeur dans des
/sequences/. Durant la phase de transcription, Python convertit les objets *mutables* (/list/ et /set/) en leur version *non mutables*:
 * Les *lists* en *tuples*,
 * Les *sets* en *frozen sets*

 #+BEGIN_SRC python :results output
 def toto():
     a = 30 * 8 * 7
     b = "TDS" * 3
     c = "T" * 4097
     d = (1, 2) * 5
     e = (10, ) * 257
     f = [101, 102] * 2
     print("Hello TDS !!!")
 
 print(f'toto function constants: {toto.__code__.co_consts}')
 print(f'toto fonction local variable names: {toto.__code__.co_varnames}')
 print(f'toto fonction non-local names: {toto.__code__.co_names}')
 #+END_SRC

 #+RESULTS:
 : toto function constants: (None, 1680, 'TDSTDSTDS', 'T', 4097, (1, 2, 1, 2, 1, 2, 1, 2, 1, 2), (10,), 257, 101, 102, 2, 'Hello TDS !!!')
 : toto fonction local variable names: ('a', 'b', 'c', 'd', 'e', 'f')
 : toto fonction non-local names: ('print',)

Commentaires :
 * ~30 * 8 * 70~ est une *expression constante* et a été évaluée à ~16800~ par le compilateur,
 * ~“TDS” * 3~ est aussi une *expression constante* et sa *longueur est <= 4096*. Elle a été évaluée à
   ~TDSTDSTDS~ par le compilateur,
 * ~“T” * 4097~, de *longueur > 4096*, n'est pas optimisée,
 * ~(1, 2) * 5~ est une séquence dont la *longueur est <= 256* (10). Elle a été évaluée et stockée comme le tuple ~(1,2,1,2,1,2,1,2,1,2)~.
 * ~(10,) * 257~ de *longueur > 256*, n'est pas optimisée,
 * ~[101, 102] * 2~ est une /list/ (objet *mutable*) et n'a pas été optimisée.

#+BEGIN_SRC python :results output
def toto():
    for a in [10, 20, 30]:
        pass

def titi():
    for a in {40, 50, 60}:
        pass

print(f'toto function constants: {toto.__code__.co_consts}') 
print(f'titi function constants: {titi.__code__.co_consts}') 
#+END_SRC

#+RESULTS:
: toto function constants: (None, (10, 20, 30))
: titi function constants: (None, frozenset({40, 50, 60}))
