No Python, um pacote de namespace permite espalhar o código Python entre vários projetos. Isso é útil quando você deseja liberar bibliotecas relacionadas como downloads separados. Por exemplo, com os diretórios Package-1
e Package-2
em PYTHONPATH
,
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
o usuário final pode import namespace.module1
e import namespace.module2
.
Qual é a melhor maneira de definir um pacote de namespace para que mais de um produto Python possa definir módulos nesse namespace?
python
namespaces
package
joeforker
fonte
fonte
Respostas:
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 apkgutil.extend_path()
solução em vez depkg_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
:foo.py
arquivofoo
contém um__init__.py
arquivofoo
sem nenhum__init__.py
arquivoPacotes 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 efoo
, se um pacote foi encontrado, a pesquisabar
é feita comfoo.__path__
o caminho de pesquisa em vez desys.path
. Sefoo.bar
for encontradofoo
efoo.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:... 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:
... e contanto que os dois
__init__.py
tenham asextend_path
linhas (epath1
,path2
epath3
estejam na suasys.path
)import package.foo
,import package.bar
eimport package.baz
todos funcionem.pkg_resources.declare_namespace(__name__)
não foi atualizado para incluir pacotes implícitos de namespace.fonte
namespace_packages
opção? E a__import__('pkg_resources').declare_namespace(__name__)
coisa?namespace_packages=['package']
osetup.py
?namespace_packages=['package']
, o setup.py adicionará umnamespace_packages.txt
no EGG-INFO. Ainda não sei os impactos ...pkg_resources.declare_namespace
excessopkgutil.extend_path
é que ele continuará a monitorarsys.path
. Dessa forma, se um novo item for adicionadosys.path
após o primeiro carregamento de um pacote no namespace, os pacotes no namespace nesse novo item de caminho ainda poderão ser carregados. (A vantagem de usar__import__('pkg_resources')
maisimport pkg_resources
é que você não acabarpkg_resources
sendo exposto comomy_namespace_pkg.pkg_resources
.)sys.path
. Quandosys.path
muda, verifica se isso afeta__path__
algum espaço para nome e, se o faz, atualiza essas__path__
propriedades.Há um módulo padrão, chamado pkgutil , com o qual você pode 'anexar' módulos a um determinado espaço para nome.
Com a estrutura de diretórios que você forneceu:
Você deve colocar essas duas linhas em ambos
Package-1/namespace/__init__.py
ePackage-2/namespace/__init__.py
(*):(* uma vez que, a menos que você declare uma dependência entre eles, você não sabe qual deles será reconhecido primeiro - consulte PEP 420 para obter mais informações)
Como a documentação diz:
A partir de agora, você poderá distribuir esses dois pacotes independentemente.
fonte
__import__
é considerado um estilo ruim neste caso, pois pode ser facilmente substituído por uma declaração de importação simples. Mais exatamente, pkg_resources é uma biblioteca não padrão. Ele vem com o setuptools, então isso não é um problema. A pesquisa rápida no Google revela que o pkgutil foi introduzido no 2.5 e o pkg_resources é anterior a ele. No entanto, o pkgutil é uma solução reconhecida oficialmente. pkg_resources inclusão foi, de fato, rejeitado em PEP 365.Package-1/namespace/__init__.py
ePackage-2/namespace/__init__.py
desde que não saibamos qual diretório do pacote está listado primeiro?Esta seção deve ser bastante auto-explicativa.
Em resumo, insira o código do espaço para nome
__init__.py
, atualizesetup.py
para declarar um espaço para nome e você estará livre para ir.fonte
Esta é uma pergunta antiga, mas alguém comentou recentemente no meu blog que minha postagem sobre pacotes de namespace ainda era relevante, então pensei em vincular a ele aqui, pois fornece um exemplo prático de como fazê-lo:
https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb
O link para este artigo mostra as principais entranhas do que está acontecendo:
http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package
O
__import__("pkg_resources").declare_namespace(__name__)
truque é basicamente impulsionar o gerenciamento de plugins no TiddlyWeb e até agora parece estar dando certo.fonte
Você tem seus conceitos de namespace do Python de trás para frente, não é possível no python colocar pacotes em módulos. Pacotes contêm módulos e não o contrário.
Um pacote Python é simplesmente uma pasta que contém um
__init__.py
arquivo. Um módulo é qualquer outro arquivo em um pacote (ou diretamente noPYTHONPATH
) que possui um.py
extensão. Portanto, no seu exemplo, você tem dois pacotes, mas nenhum módulo definido. Se você considerar que um pacote é uma pasta do sistema de arquivos e um módulo é um arquivo, você verá por que os pacotes contêm módulos e não o contrário.Portanto, no seu exemplo, assumindo que o Pacote 1 e o Pacote 2 sejam pastas no sistema de arquivos que você colocou no caminho do Python, você pode ter o seguinte:
Agora você tem um pacote
namespace
com dois módulosmodule1
emodule2
. e, a menos que você tenha um bom motivo, provavelmente deverá colocar os módulos na pasta e ter apenas isso no caminho do python, como abaixo:fonte
zope.x
onde um monte de pacotes relacionados é lançado como downloads separados.