En Python, un paquete de espacio de nombres le permite distribuir el código de Python entre varios proyectos. Esto es útil cuando desea lanzar bibliotecas relacionadas como descargas separadas. Por ejemplo, con los directorios Package-1
y Package-2
en PYTHONPATH
,
Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py
el usuario final puede import namespace.module1
y import namespace.module2
.
¿Cuál es la mejor manera de definir un paquete de espacio de nombres para que más de un producto Python pueda definir módulos en ese espacio de nombres?
python
namespaces
package
joeforker
fuente
fuente
Respuestas:
TL; DR:
En Python 3.3 no tiene que hacer nada, simplemente no coloque ninguno
__init__.py
en sus directorios de paquetes de espacio de nombres y simplemente funcionará. En pre-3.3, elija lapkgutil.extend_path()
solución sobre la anteriorpkg_resources.declare_namespace()
, porque es a prueba de futuro y ya es compatible con paquetes de espacio de nombres implícitos.Python 3.3 introduce paquetes de espacio de nombres implícitos, ver PEP 420 .
Esto significa que ahora hay tres tipos de objetos que pueden ser creados por un
import foo
:foo.py
archivofoo
contiene un__init__.py
archivofoo
sin ningún__init__.py
archivoLos paquetes también son módulos, pero aquí me refiero a "módulo sin paquete" cuando digo "módulo".
Primero busca
sys.path
un módulo o paquete normal. Si tiene éxito, deja de buscar y crea e inicializa el módulo o paquete. Si no encontró ningún módulo o paquete normal, pero encontró al menos un directorio, crea e inicializa un paquete de espacio de nombres.Los módulos y paquetes regulares se han
__file__
configurado en el.py
archivo desde el que se crearon. Los paquetes regulares y de espacio de nombres se han__path__
establecido en el directorio o directorios a partir de los cuales fueron creados.Cuando lo haga
import foo.bar
, la búsqueda anterior se realiza primerofoo
, luego, si se encontró un paquete, la búsquedabar
se realizafoo.__path__
como la ruta de búsqueda en lugar desys.path
. Sifoo.bar
se encuentrafoo
yfoo.bar
se crea e inicializa.Entonces, ¿cómo se mezclan los paquetes regulares y los paquetes de espacio de nombres? Normalmente no lo hacen, pero el antiguo
pkgutil
método de paquete de espacio de nombres explícito se ha ampliado para incluir paquetes de espacio de nombres implícitos.Si tiene un paquete regular existente que tiene un
__init__.py
aspecto como este:... el comportamiento heredado es agregar cualquier otro paquete regular en la ruta buscada
__path__
. Pero en Python 3.3, también agrega paquetes de espacio de nombres.Para que pueda tener la siguiente estructura de directorios:
... y siempre y cuando los dos
__init__.py
tengan lasextend_path
líneas (ypath1
,path2
ypath3
estén en susys.path
)import package.foo
,import package.bar
yimport package.baz
todos funcionen.pkg_resources.declare_namespace(__name__)
no se ha actualizado para incluir paquetes de espacio de nombres implícitos.fuente
namespace_packages
opción? Y la__import__('pkg_resources').declare_namespace(__name__)
cosa?namespace_packages=['package']
elsetup.py
?namespace_packages=['package']
, setup.py agregará unnamespace_packages.txt
en EGG-INFO. Todavía no conozco los impactos ...pkg_resources.declare_namespace
overpkgutil.extend_path
es que continuará monitoreandosys.path
. De esa manera, si se agrega un nuevo elementosys.path
después de que un paquete en el espacio de nombres se carga por primera vez, los paquetes en el espacio de nombres en ese nuevo elemento de ruta aún se pueden cargar. (Una ventaja de usar__import__('pkg_resources')
másimport pkg_resources
es que no terminaspkg_resources
expuesto comomy_namespace_pkg.pkg_resources
.)sys.path
. Cuandosys.path
cambia, verifica si eso afecta el__path__
espacio de nombres, y si lo hace, actualiza esas__path__
propiedades.Hay un módulo estándar, llamado pkgutil , con el que puede 'agregar' módulos a un espacio de nombres dado.
Con la estructura de directorios que ha proporcionado:
Debe poner esas dos líneas en ambos
Package-1/namespace/__init__.py
yPackage-2/namespace/__init__.py
(*):(* dado que, a menos que establezca una dependencia entre ellos, no sabe cuál de ellos se reconocerá primero; consulte PEP 420 para obtener más información)
Como dice la documentación :
A partir de ahora, debería poder distribuir esos dos paquetes de forma independiente.
fuente
__import__
se considera un mal estilo en este caso, ya que se puede reemplazar fácilmente con una declaración de importación simple. Más concretamente, pkg_resources es una biblioteca no estándar. Viene con herramientas de configuración, por lo que no es un problema. Google rápido revela que pkgutil se introdujo en 2.5 y pkg_resources es anterior a él. Sin embargo, pkgutil es una solución oficialmente reconocida. La inclusión de pkg_resources fue, de hecho, rechazada en PEP 365.Package-1/namespace/__init__.py
yPackage-2/namespace/__init__.py
siempre que no sepamos qué paquete de directorios aparece primero?Esta sección debería explicarse bastante por sí misma.
En resumen, ingrese el código del espacio de nombres
__init__.py
, actualícelosetup.py
para declarar un espacio de nombres y tendrá libertad para continuar.fuente
Esta es una vieja pregunta, pero alguien comentó recientemente en mi blog que mi publicación sobre paquetes de espacios de nombres aún era relevante, por lo que pensé en vincularla aquí ya que proporciona un ejemplo práctico de cómo hacerlo:
https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb
Eso enlaza a este artículo para conocer las principales agallas de lo que está sucediendo:
http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package
El
__import__("pkg_resources").declare_namespace(__name__)
truco consiste en impulsar la administración de complementos en TiddlyWeb y hasta ahora parece estar funcionando.fuente
Tiene sus conceptos de espacio de nombres de Python al frente, no es posible en python poner paquetes en módulos. Los paquetes contienen módulos, no al revés.
Un paquete de Python es simplemente una carpeta que contiene un
__init__.py
archivo. Un módulo es cualquier otro archivo en un paquete (o directamente en elPYTHONPATH
) que tenga una.py
extensión. Entonces, en su ejemplo, tiene dos paquetes pero no hay módulos definidos. Si considera que un paquete es una carpeta del sistema de archivos y un módulo es un archivo, entonces verá por qué los paquetes contienen módulos y no al revés.Entonces, en su ejemplo, suponiendo que Package-1 y Package-2 son carpetas en el sistema de archivos que ha colocado en la ruta de Python, puede tener lo siguiente:
Ahora tiene un paquete
namespace
con dos módulosmodule1
ymodule2
. y a menos que tenga una buena razón, probablemente debería poner los módulos en la carpeta y tener solo eso en la ruta de Python como a continuación:fuente
zope.x
donde se lanzan un montón de paquetes relacionados como descargas separadas.