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-1y Package-2en 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.module1y 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__.pyen 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.pyarchivofoocontiene un__init__.pyarchivofoosin ningún__init__.pyarchivoLos paquetes también son módulos, pero aquí me refiero a "módulo sin paquete" cuando digo "módulo".
Primero busca
sys.pathun 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.pyarchivo 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úsquedabarse realizafoo.__path__como la ruta de búsqueda en lugar desys.path. Sifoo.barse encuentrafooyfoo.barse 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
pkgutilmé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__.pyaspecto 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__.pytengan lasextend_pathlíneas (ypath1,path2ypath3estén en susys.path)import package.foo,import package.baryimport package.baztodos funcionen.pkg_resources.declare_namespace(__name__)no se ha actualizado para incluir paquetes de espacio de nombres implícitos.fuente
namespace_packagesopción? Y la__import__('pkg_resources').declare_namespace(__name__)cosa?namespace_packages=['package']elsetup.py?namespace_packages=['package'], setup.py agregará unnamespace_packages.txten EGG-INFO. Todavía no conozco los impactos ...pkg_resources.declare_namespaceoverpkgutil.extend_pathes que continuará monitoreandosys.path. De esa manera, si se agrega un nuevo elementosys.pathdespué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_resourceses que no terminaspkg_resourcesexpuesto comomy_namespace_pkg.pkg_resources.)sys.path. Cuandosys.pathcambia, 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__.pyyPackage-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__.pyyPackage-2/namespace/__init__.pysiempre 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.pypara 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__.pyarchivo. Un módulo es cualquier otro archivo en un paquete (o directamente en elPYTHONPATH) que tenga una.pyextensió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
namespacecon dos módulosmodule1ymodule2. 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.xdonde se lanzan un montón de paquetes relacionados como descargas separadas.