TL; DR:
No Python 3.3, você não precisa fazer nada, apenas não coloque nenhum __init__.pyem 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.pyarquivo
- Um pacote regular, representado por um diretório que
foocontém um __init__.pyarquivo
- Um pacote de namespace, representado por um ou mais diretórios
foosem nenhum __init__.pyarquivo
Pacotes também são módulos, mas aqui quero dizer "módulo sem pacote" quando digo "módulo".
Primeiro, ele procura sys.pathpor 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 .pyarquivo 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.barfor encontrado fooe foo.barcriado e inicializado.
Então, como os pacotes regulares e os pacotes de namespace se misturam? Normalmente não, mas o pkgutilmé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__.pyaparê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__.pytenham as extend_pathlinhas (e path1, path2e path3estejam na sua sys.path) import package.foo, import package.bare import package.baztodos funcionem.
pkg_resources.declare_namespace(__name__) não foi atualizado para incluir pacotes implícitos de namespace.