9.2. Les paquetages

Analyser un document XML est pour l'heure chose très simple : cela tient sur une ligne de code. Cependant, avant que vous n'abordiez cette ligne de code, une digression s'impose pour parler des paquetages.

Exemple 9.5. Charger un document XML (bref aperçu)

>>> from xml.dom import minidom 1
>>> xmldoc = minidom.parse('~/diveintopython/common/py/kgp/binary.xml')
1 Vous n'aviez pas encore vu cette syntaxe. Elle ressemble presque à votre cher from module import, mais le "." montre que c'est quelque chose de plus qu'un simple import. En fait, xml est bien le paquetage, dom un paquetage imbriqué dans xml et minidom un module de xml.dom.

Cela paraît compliqué, mais il n'en est rien. Un examen de l'implémentation réelle peut aider. Les paquetages sont un peu plus que des répertoires de modules; les paquetages imbriqués sont les sous-répertoires. Les modules au sein d'un paquetage (ou d'un paquetage imbriqué) sont juste des fichiers .py, comme toujours, sauf qu'ils sont rangés dans un sous-répertoire plutôt que dans le répertoire principal lib/ de votre installation Python.

Exemple 9.6. La disposition des fichiers dans un paquetage

Python21/           root Python installation (home of the executable)
|
+--lib/             library directory (home of the standard library modules)
   |
   +-- xml/         xml package (really just a directory with other stuff in it)
       |
       +--sax/      xml.sax package (again, just a directory)
       |
       +--dom/      xml.dom package (contains minidom.py)
       |
       +--parsers/  xml.parsers package (used internally)

Ainsi, lorsque vous écrivez from xml.dom import minidom, Python comprend la chose suivante : «rechercher dans le répertoire xml un répertoire dom, rechercher dans ce répertoire le module minidom et l'importer en tant que minidom». Mais Python est beaucoup plus astucieux que cela; non seulement il vous est possible d'importer la totalité des modules d'un paquetage, mais il est encore possible de sélectionner des classes ou des fonctions spécifiques à l'intérieur d'un module. Il vous est également possible d'importer le paquetage lui-même comme un module. La syntaxe est toujours la même; Python comprend ce à quoi vous faites référence à partir de la disposition des fichiers dans le paquetage, et s'exécute automatiquement.

Exemple 9.7. Les paquetages sont aussi des modules

>>> from xml.dom import minidom         1
>>> minidom
<module 'xml.dom.minidom' from 'C:\Python21\lib\xml\dom\minidom.pyc'>
>>> minidom.Element
<class xml.dom.minidom.Element at 01095744>
>>> from xml.dom.minidom import Element 2
>>> Element
<class xml.dom.minidom.Element at 01095744>
>>> minidom.Element
<class xml.dom.minidom.Element at 01095744>
>>> from xml import dom                 3
>>> dom
<module 'xml.dom' from 'C:\Python21\lib\xml\dom\__init__.pyc'>
>>> import xml                          4
>>> xml
<module 'xml' from 'C:\Python21\lib\xml\__init__.pyc'>
1 Ici vous importez un module (minidom) à partir d'un paquetage imbriqué (xml.dom). Il en résulte que minidom est importé dans votre espace de nom et que pour référencer les classes du module minidom (comme Element), vous devez les faire précéder du nom du module.
2 Ici vous importez la classe (Element) d'un module (minidom) à partir d'un paquetage imbriqué (xml.dom). Il en résulte que Element est importé directement dans votre espace de noms. Remarquez que cela n'interfère aucunement avec la précédente importation, la classe Element peut désormais être référencée de deux façons (mais il s'agit toujours de la même classe).
3 Ici vous importez le paquetage dom (un paquetage imbriqué de xml) en tant que module. Chaque niveau d'un paquetage peut être considéré comme un module, comme vous le verrez plus loin. Il peut même posséder ses propres attributs et méthodes, comme les modules que vous avez vus précédemment.
4 Ici vous importez le paquetage racine xml comme un module.

Mais alors, comment un paquetage (c'est-à-dire un répertoire) peut-il être importé et traité comme un module (c'est-à-dire un fichier) ? Par la magie du fichier __init__.py. Les paquetages ne sont pas de simples répertoires; ce sont des répertoires qui contiennent un fichier spécifique, __init__.py. Ce fichier définit les attributs et les méthodes du paquetage. Par exemple, xml.dom contient une classe Node, laquelle est définie dans xml/dom/__init__.py. Lorsque vous importez un paquetage en tant que module (comme dom à partir de xml), vous importez aussi son fichier __init__.py.

NOTE
Un paquetage est un répertoire pourvu du fichier __init__.py. Le fichier __init__.py définit les attributs et les méthodes du paquetage. Il n'est cependant pas tenu de définir quoi que ce soit; ce peut simplement être un fichier vide, mais il se doit d'être présent. Et si __init__.py n'existe pas, le répertoire reste un répertoire, pas un paquetage et ne peut ni être importé ni contenir de modules ou de paquetages imbriqués.

Pourquoi s'embêter avec des paquetages ? C'est qu'ils permettent de regrouper logiquement des modules associés. Plutôt que d'avoir un paquetage xml contenant les paquetages sax et dom, les auteurs auraient pu décider de ranger toutes les fonctionnalités de sax dans le fichier xmlsax.py et de la même façon les fonctionnalités de dom dans xmldom.py, voire même de n'en faire qu'un seul module. Mais cela aurait été peu maniable (à ce jour, le paquetage XML contient plus de 3000 lignes de code) et difficile à gérer (des fichiers sources séparés permettent à plusieurs personnes de travailler simultanément à différents endroits du code).

Si vous vous retrouvez à écrire un long sous-système en Python (ou, plus probablement, quand vous vous rendrez compte que votre petit sous-système s'est énormément développé), prenez le temps de construire une solide architecture de paquetage. C'est là encore l'un des nombreux avantages de Python, alors profitez-en.