TL; DR:
Sur Python 3.3, vous n'avez rien à faire, n'en mettez tout simplement pas __init__.py
dans les répertoires de vos packages d'espace de noms et cela fonctionnera. Sur la version antérieure à la version 3.3, choisissez la pkgutil.extend_path()
solution plutôt que pkg_resources.declare_namespace()
celle, car elle est à l'épreuve du temps et déjà compatible avec les packages d'espace de noms implicites.
Python 3.3 introduit les packages d'espace de noms implicites, voir PEP 420 .
Cela signifie qu'il existe désormais trois types d'objets qui peuvent être créés par un import foo
:
- Un module représenté par un
foo.py
fichier
- Un package régulier, représenté par un répertoire
foo
contenant un __init__.py
fichier
- Un package d'espace de noms, représenté par un ou plusieurs répertoires
foo
sans aucun __init__.py
fichier
Les packages sont aussi des modules, mais ici je veux dire "module non-package" quand je dis "module".
Il recherche sys.path
d'abord un module ou un package standard. S'il réussit, il arrête la recherche et crée et initialise le module ou le package. S'il n'a trouvé aucun module ou package normal, mais qu'il a trouvé au moins un répertoire, il crée et initialise un package d'espace de noms.
Les modules et les packages normaux sont __file__
définis sur le .py
fichier à partir duquel ils ont été créés. Les packages standard et d'espace de noms sont __path__
définis sur le ou les répertoires à partir desquels ils ont été créés.
Lorsque vous le faites import foo.bar
, la recherche ci-dessus se produit d'abord pour foo
, puis si un package a été trouvé, la recherche bar
est effectuée avec foo.__path__
comme chemin de recherche au lieu de sys.path
. Si foo.bar
on trouve, foo
et foo.bar
sont créés et initialisés.
Alors, comment se mélangent les packages standards et les packages d'espace de noms? Normalement, ce n'est pas le cas, mais l'ancienne pkgutil
méthode de package d'espace de noms explicite a été étendue pour inclure des packages d'espace de noms implicites.
Si vous avez un package régulier existant qui a un __init__.py
comme ceci:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
... le comportement hérité consiste à ajouter tous les autres packages réguliers sur le chemin recherché à son __path__
. Mais dans Python 3.3, il ajoute également des packages d'espace de noms.
Vous pouvez donc avoir la structure de répertoires suivante:
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
... et tant que les deux __init__.py
ont les extend_path
lignes (et path1
, path2
et path3
sont dans votre sys.path
) import package.foo
, import package.bar
et import package.baz
tout fonctionnera.
pkg_resources.declare_namespace(__name__)
n'a pas été mis à jour pour inclure les packages d'espace de noms implicites.