PEP 3147

J’aime vraiment lire les notes de versions de Python. Toujours très réjouissantes, pleines de nouveautés. C’est pourquoi j’ai souvent différentes versions de Python sur mes systèmes. Et parfois trop pressé de tester des nouveautés je sème le cahos dans mes projets.

Cette fois ce n’est pas un nouveau module, ou une nouvelle fonction. Il s’agit simplement d’une petite amélioration de la gestion des fichiers compilés. CPython compile les sources importés en byte code (.pyc) pour optimiser les performances. Il réutilise directement les .pyc par la suite.
Grâce au PEP 3147 il est plus facile de partager du code Python. Plusieurs fichiers compilés peuvent coexister. En effet, comme nous n’avons pas tous exactement la même version de Python, nous ne générons pas forcément les mêmes fichiers byte code.

$ ls -Rl test/
test/:
total 4
-rw-r--r-- 1 cedric cedric  0 2011-03-11 21:14 __init__.py
-rw-r--r-- 1 cedric cedric 12 2011-03-11 21:14 one.py

$ python3.2 -c "import test"

$ ls -Rl test/
test/:
total 8
-rw-r--r-- 1 cedric cedric    0 2011-03-11 21:14 __init__.py
-rw-r--r-- 1 cedric cedric   12 2011-03-11 21:14 one.py
drwxr-xr-x 2 cedric cedric 4096 2011-03-11 21:23 __pycache__

test/__pycache__:
total 4
-rw-r--r-- 1 cedric cedric 107 2011-03-11 21:23 __init__.cpython-32.pyc

Voyez le nouveau dossier __pycache__ qui a été créé. Le premier effet est d’avoir des dossiers mieux rangés. On peut ignorer le dossier de cache lorsque l’on représente la hiérarchie d’un projet, c’est plus propre. Mais ça peut aussi éviter à certains malins de supprimer par mégarde un .py à la place d’un .pyc (rm *.py, pauvre toi).

Voici un organigramme résumant la situation. Ça n’a rien de compliqué et on peut rapidement revoir comment fonctionne les imports et la génération de byte code.

La première fois qu’un module est appelé, Python vérifie la présence du source, du cache et du .pyc. La première fois il faudra évidemment créer le cache et le .pyc (avec le nombre magique correspondant au source) à partir du source.
Les fois suivantes Python vérifie toujours la présence du source, puis devrait trouver le .pyc dans le cache. Si le source n’as pas changé (et qu’il s’agit du même interpréteur Python) le nombre magique est correct, il peut charger le .pyc. Si le nombre magique est mauvais, le .pyc est régénéré.
Python vérifie toujours la présence du source en premier. Si le .pyc est présent (supposons à jour) et que le source n’est pas là, une erreur est générée. Ça se passe comme ça dans la majeure partie des cas, plus de détails ici.