TL; DR:
No Python 3.3, você não precisa fazer nada, apenas não coloque nenhum __init__.py
em seus diretórios de pacotes de espaço para nome e ele simplesmente funcionará. Na versão anterior à 3.3, escolha a pkgutil.extend_path()
solução em vez de pkg_resources.declare_namespace()
outra, porque ela é à prova do futuro e já é compatível com pacotes de espaço para nome implícitos.
O Python 3.3 apresenta pacotes implícitos de namespace, consulte PEP 420 .
Isso significa que agora existem três tipos de objetos que podem ser criados por um import foo
:
- Um módulo representado por um
foo.py
arquivo
- Um pacote regular, representado por um diretório que
foo
contém um __init__.py
arquivo
- Um pacote de namespace, representado por um ou mais diretórios
foo
sem nenhum __init__.py
arquivo
Pacotes também são módulos, mas aqui quero dizer "módulo sem pacote" quando digo "módulo".
Primeiro, ele procura sys.path
por um módulo ou pacote regular. Se for bem-sucedido, ele interrompe a pesquisa e cria e inicializa o módulo ou pacote. Se não encontrou nenhum módulo ou pacote regular, mas encontrou pelo menos um diretório, ele cria e inicializa um pacote de namespace.
Módulos e pacotes regulares foram __file__
definidos para o .py
arquivo de onde foram criados. Pacotes regulares e de namespace foram __path__
definidos para o diretório ou diretórios dos quais foram criados.
Quando você faz isso import foo.bar
, a pesquisa acima acontece primeiro e foo
, se um pacote foi encontrado, a pesquisa bar
é feita com foo.__path__
o caminho de pesquisa em vez de sys.path
. Se foo.bar
for encontrado foo
e foo.bar
criado e inicializado.
Então, como os pacotes regulares e os pacotes de namespace se misturam? Normalmente não, mas o pkgutil
método antigo do pacote de espaço para nome explícito foi estendido para incluir pacotes implícitos de espaço para nome.
Se você possui um pacote regular que possui uma __init__.py
aparência semelhante a esta:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
... o comportamento herdado é adicionar outros pacotes regulares no caminho pesquisado ao seu __path__
. Mas no Python 3.3, ele também adiciona pacotes de namespace.
Então você pode ter a seguinte estrutura de diretórios:
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
... e contanto que os dois __init__.py
tenham as extend_path
linhas (e path1
, path2
e path3
estejam na sua sys.path
) import package.foo
, import package.bar
e import package.baz
todos funcionem.
pkg_resources.declare_namespace(__name__)
não foi atualizado para incluir pacotes implícitos de namespace.