TL; DR:
В Python 3.3 вам не нужно ничего делать, просто не помещайте ничего __init__.pyв каталоги пакетов вашего пространства имен, и это будет работать. В версиях до 3.3 выберите pkgutil.extend_path()решение вместо pkg_resources.declare_namespace()одного, потому что оно ориентировано на будущее и уже совместимо с пакетами неявных пространств имен.
Python 3.3 представляет пакеты неявного пространства имен, см. PEP 420 .
Это означает, что теперь есть три типа объектов, которые могут быть созданы import foo:
- Модуль, представленный
foo.pyфайлом
- Обычный пакет, представленный каталогом,
fooсодержащим __init__.pyфайл
- Пакет пространства имен, представленный одним или несколькими каталогами
fooбез __init__.pyфайлов.
Пакеты тоже являются модулями, но здесь я имею в виду «не пакетный модуль», когда говорю «модуль».
Сначала sys.pathвыполняется поиск модуля или обычного пакета. В случае успеха поиск прекращается, создается и инициализируется модуль или пакет. Если он не нашел ни модуля, ни обычного пакета, но нашел хотя бы один каталог, он создает и инициализирует пакет пространства имен.
Модули и обычные пакеты __file__установили в .pyфайл, из которого они были созданы. Обычные пакеты и пакеты пространства имен __path__установлены в каталог или каталоги, из которых они были созданы.
Когда вы это сделаете import foo.bar, указанный выше поиск выполняется сначала для foo, а затем, если пакет был найден, поиск barвыполняется с foo.__path__использованием пути поиска вместо sys.path. Если foo.barобнаруживается, fooи foo.barсоздаются и инициализируются.
Так как же смешиваются обычные пакеты и пакеты пространства имен? Обычно это не так, но старый pkgutilметод пакета явного пространства имен был расширен за счет включения неявных пакетов пространства имен.
Если у вас есть существующий обычный пакет, который выглядит примерно __init__.pyтак:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
... унаследованное поведение заключается в добавлении любых других обычных пакетов по искомому пути к его __path__. Но в Python 3.3 он также добавляет пакеты пространства имен.
Таким образом, у вас может быть следующая структура каталогов:
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
... и пока у двух __init__.pyесть extend_pathстроки (и path1, path2и path3в вашем sys.path) import package.foo, import package.barи import package.bazвсе будет работать.
pkg_resources.declare_namespace(__name__) не был обновлен для включения неявных пакетов пространства имен.