Les Crash-Devs d'un Passionné

La signification des extensions .pyo

/Catégorie/python

Temps de lecture : 3 minutes

Sur les versions antérieures à python 3.5 l'interpréteur nous donnait la possibilité de générer du binaire optimisé dans un fichier spécifique pyo.

L'interpréteur python (par défaut CPython) peut recevoir une option :

  • -O pour générer un fichier optimisé
  • -OO la même chose que -O mais en enlevant les valeurs de __doc__

On peut également enregistrer cette valeur dans une variable d'environnement

  • PYTHONOPTIMIZE=0 (pas d'option)
  • PYTHONOPTIMIZE=1 est équivalent à -O
  • PYTHONOPTIMIZE=2 est équivalent à -OO

Pour forcer la génération du bytecode il suffit d'appeler le module compileall qui est une librairie standard. Et vous voyez la génération des fichiers optimisés dans le dossier __cache__

$ ls -l __pycache__/ 

-rw-r--r-- 1 david david 119 juil. 25 12:34 file.cpython-310.opt-1.pyc

Dans le nom du fichier optimisé on retrouve

  • le fichier : file
  • l'interpréteur : CPython
  • la version du python : 3.10
  • l'option d'optimisation : opt-1 ou opt-2
  • l'extension : pyc (car en python >=3.5 le pyo n'est pas utilisé, l'optimisation est comprise dans le pyc)

Lorsque cette option est activée, par exemple il n'est pas possible d'utiliser pdb car __debug__ vaudra False

Un autre point à connaître est la suppression des

assert

lorsque le flag est utilisé

Voici le cas d'exemple

clipboard
Copier le code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# file.py
print('hello')
assert False

# Interpreter
$ export PYTHONOPTIMIZE=0
$ python3 file.py 
hello
Traceback (most recent call last):
  File "/home/david/Downloads/test/file.py", line 2, in <module>
    assert False
AssertionError

Et celui avec l'optimisation

clipboard
Copier le code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# file.py
print('hello')
assert False

# Interpreter
$ export PYTHONOPTIMIZE=2
$ python3 -m compileall file.py 
Compiling 'file.py'...
$ python3 file.py 
hello

Il est important de préciser que de passer par un pyo ou même pyc ne rend pas le programme plus rapide, mais le charge plus rapidement en mémoire

clipboard
Copier le code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import timeit
result = timeit.timeit("print('hello')", number=100000)
print(result)


# python file.py without flag -OO
# 0.888337237000087

#  python file.py without flag -OO
# 0.9634458870023082

Sur les dernières versions de python il n'est pas recommandé d'utiliser cette option : PEP 488