TL;DR :
Sous Python 3.3, vous n'avez rien à faire, il suffit de ne pas mettre de __init__.py
dans les répertoires des paquets de votre espace de nom et cela fonctionnera tout simplement. Sur les versions antérieures à 3.3, choisissez l'option pkgutil.extend_path()
sur le pkg_resources.declare_namespace()
car il est à l'épreuve du temps et déjà compatible avec les paquets d'espaces de noms implicites.
Python 3.3 introduit les paquets d'espaces de noms implicites, cf. PEP 420 .
Cela signifie qu'il y a maintenant trois types d'objets qui peuvent être créés par un agent de l'UE. import foo
:
- Un module représenté par un
foo.py
fichier
- Un paquet régulier, représenté par un répertoire
foo
contenant un __init__.py
fichier
- Un paquet d'espace de nom, représenté par un ou plusieurs répertoires
foo
sans aucune __init__.py
fichiers
Les paquets sont aussi des modules, mais ici, quand je dis "module", je veux dire "module non paquet".
D'abord, il scanne sys.path
pour un module ou un paquet régulier. S'il y parvient, il arrête la recherche et crée et initialise le module ou le paquet. S'il n'a pas trouvé de module ou de paquet régulier, mais qu'il a trouvé au moins un répertoire, il crée et initialise un paquet d'espace de nom.
Les modules et les paquets réguliers ont __file__
fixé à la .py
à partir duquel ils ont été créés. Les paquets réguliers et les paquets d'espace de nom ont __path__
dans le ou les répertoires à partir desquels ils ont été créés.
Quand vous le faites import foo.bar
la recherche ci-dessus se fait d'abord pour foo
puis, si un paquet a été trouvé, la recherche de bar
se fait avec foo.__path__
comme chemin de recherche au lieu de sys.path
. Si foo.bar
est trouvé, foo
y foo.bar
sont créés et initialisés.
Alors, comment les paquets ordinaires et les paquets de l'espace de nom se mélangent-ils ? Normalement, ils ne se mélangent pas, mais l'ancien système de pkgutil
La méthode des paquets d'espace de noms explicites a été étendue pour inclure les paquets d'espace de noms implicites.
Si vous disposez d'un paquet régulier existant qui possède un fichier __init__.py
comme ça :
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
... l'ancien comportement consiste à ajouter toute autre régulier sur le chemin recherché vers son __path__
. Mais dans Python 3.3, il ajoute également des packages d'espace de noms.
Vous pouvez donc avoir la structure de répertoire suivante :
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
... et aussi longtemps que les deux __init__.py
ont le extend_path
lignes (et path1
, path2
y path3
sont dans votre sys.path
) import package.foo
, import package.bar
y import package.baz
fonctionneront tous.
pkg_resources.declare_namespace(__name__)
n'a pas été mis à jour pour inclure les paquets implicites de l'espace de noms.
7 votes
Il me semble que module1 et module2 sont en fait des sous-paquets plutôt que des modules. D'après ce que j'ai compris, un module est en fait un fichier unique. Peut-être que subpkg1 et subpkg2 auraient plus de sens comme noms ?