Quiero heredar de una clase en un archivo que se encuentra en un directorio sobre el actual.
¿Es posible importar relativamente ese archivo?
fuente
Quiero heredar de una clase en un archivo que se encuentra en un directorio sobre el actual.
¿Es posible importar relativamente ese archivo?
from ..subpkg2 import mod
Según los documentos de Python: cuando esté dentro de una jerarquía de paquetes, use dos puntos, como dice el documento de la declaración de importación :
Al especificar qué módulo importar no tiene que especificar el nombre absoluto del módulo. Cuando un módulo o paquete está contenido dentro de otro paquete, es posible realizar una importación relativa dentro del mismo paquete superior sin tener que mencionar el nombre del paquete. Al utilizar puntos iniciales en el módulo o paquete
from
especificado, puede especificar qué tan alto recorrer la jerarquía de paquetes actual sin especificar nombres exactos. Un punto inicial significa el paquete actual donde existe el módulo que realiza la importación. Dos puntos significan un nivel de paquete . Tres puntos son dos niveles, etc. Entonces, si ejecutafrom . import mod
desde un módulo en elpkg
paquete, terminará importandopkg.mod
. Si ejecutafrom ..subpkg2 import mod
desde dentropkg.subpkg1
, importarápkg.subpkg2.mod
. La especificación para las importaciones relativas está contenida en PEP 328 .
PEP 328 trata de importaciones absolutas / relativas.
fuente
La respuesta de @ gimel es correcta si puede garantizar la jerarquía de paquetes que menciona. Si no puede, si su necesidad real es como la expresó, vinculada exclusivamente a los directorios y sin ninguna relación necesaria con el empaquetado, entonces necesita trabajar
__file__
para encontrar el directorio principal (un par deos.path.dirname
llamadas funcionarán; -), entonces (si ese directorio no está ya ensys.path
) prepend temporalmente dicho inserto dir en el comienzo mismo desys.path
,__import__
, retire dijo dir de nuevo - el trabajo sucio de hecho, pero, "cuando es necesario, debe" (y se esfuerza a Phyton nunca detenga al programador de hacer lo que debe hacerse, ¡como dice el estándar ISO C en la sección "Espíritu de C" en su prefacio! -).Aquí hay un ejemplo que puede funcionar para usted:
fuente
sys.path
que el mismo módulo esté disponible con diferentes nombres y todos los errores correspondientes. autopath.py en pypy o _preamble.py en retorcido lo resuelven usando un criterio de búsqueda que identifica el paquete de nivel superior mientras recorre los directorios hacia arriba.sys.path.remove(pathYouJustAdded)
después de la importación que necesitaba para no retener esta nueva ruta.Importe el módulo desde un directorio que esté exactamente un nivel por encima del directorio actual:
fuente
from .. import module
recibí el error ValueError: Intenté la importación relativa en un paquete sin seguir la recomendaciónCómo cargar un módulo que es un directorio arriba
Prefacio: Realicé una reescritura sustancial de una respuesta anterior con la esperanza de ayudar a las personas a entrar en el ecosistema de Python y, con suerte, darles a todos el mejor cambio de éxito con el sistema de importación de Python.
Esto cubrirá las importaciones relativas dentro de un paquete , que creo que es el caso más probable de la pregunta de OP.
Python es un sistema modular
Es por eso que escribimos
import foo
para cargar un módulo "foo" desde el espacio de nombres raíz, en lugar de escribir:Python no está acoplado a un sistema de archivos
Es por eso que podemos incrustar python en un entorno donde no hay un sistema de archivos de facto sin proporcionar uno virtual, como Jython.
Estar desacoplado de un sistema de archivos permite que las importaciones sean flexibles, este diseño permite cosas como importaciones de archivos comprimidos / zip, importación de singletons, almacenamiento en caché de byte, extensiones cffi, incluso la carga remota de definiciones de código.
Entonces, si las importaciones no están acopladas a un sistema de archivos, ¿qué significa "un directorio arriba"? Tenemos que elegir algunas heurísticas, pero podemos hacerlo, por ejemplo, cuando trabajamos dentro de un paquete , ya se han definido algunas heurísticas que hacen que a las importaciones relativas les guste
.foo
y..foo
funcionen dentro del mismo paquete. ¡Frio!Si sinceramente desea acoplar sus patrones de carga de código fuente a un sistema de archivos, puede hacerlo. Tendrá que elegir sus propias heurísticas y utilizar algún tipo de maquinaria de importación. Recomiendo importlib
El ejemplo importlib de Python se ve así:
embalaje
Hay un gran proyecto de ejemplo disponible oficialmente aquí: https://github.com/pypa/sampleproject
Un paquete de Python es una recopilación de información sobre su código fuente, que puede informar a otras herramientas cómo copiar su código fuente en otras computadoras y cómo integrar su código fuente en la ruta de ese sistema para que
import foo
funcione para otras computadoras (independientemente del intérprete, sistema operativo host, etc.)Estructura de directorios
Tengamos un nombre de paquete
foo
, en algún directorio (preferiblemente un directorio vacío).Mi preferencia es crear
setup.py
como hermanofoo.py
, porque hace que escribir el archivo setup.py sea más simple, sin embargo, puede escribir la configuración para cambiar / redirigir todo lo que setuptools hace de manera predeterminada si lo desea; por ejemplo, ponerfoo.py
bajo un directorio "src /" es algo popular, no cubierto aquí..
.
"editable", también conocido
-e
, redirigirá una vez más la maquinaria de importación para cargar los archivos de origen en este directorio, en lugar de copiar los archivos exactos actuales en la biblioteca del entorno de instalación. Esto también puede causar diferencias de comportamiento en la máquina de un desarrollador, ¡asegúrese de probar su código! Hay otras herramientas además de pip, sin embargo, recomendaría que pip sea el introductorio :)También me gusta hacer
foo
un "paquete" (un directorio que contenga__init__.py
) en lugar de un módulo (un solo archivo ".py"), tanto "paquetes" como "módulos" se pueden cargar en el espacio de nombres raíz, los módulos permiten espacios de nombres anidados, lo cual es útil si queremos tener una importación "relativa a un directorio arriba"..
También me gusta hacer un
foo/__main__.py
, esto permite que Python ejecute el paquete como un módulo, por ejemplo,python3 -m foo
se ejecutaráfoo/__main__.py
como__main__
..
Vamos a desarrollar esto con algunos módulos más: Básicamente, puede tener una estructura de directorios como esta:
setup.py
convencionalmente contiene información de metadatos sobre el código fuente, como:foo
, aunque sustituir guiones de subrayado por guiones es popularpython ./setup.py test
Es muy expansivo, incluso puede compilar extensiones C sobre la marcha si se instala un módulo fuente en una máquina de desarrollo. Para un ejemplo de todos los días, recomiendo setup.py del repositorio de muestras PYPA.
Si está lanzando un artefacto de compilación, por ejemplo, una copia del código destinado a ejecutar computadoras casi idénticas, un archivo require.txt es una forma popular de capturar información de dependencia exacta, donde "install_requires" es una buena manera de capturar el mínimo y Máximas versiones compatibles. Sin embargo, dado que las máquinas de destino son casi idénticas de todos modos, recomiendo crear un tarball de un prefijo completo de python. Esto puede ser complicado, demasiado detallado para entrar aquí. Echa un vistazo a
pip install
la--target
opción, o virtualenv aka venv para clientes potenciales.volviendo al ejemplo
cómo importar un archivo un directorio arriba:
Desde foo / spam / eggs.py, si quisiéramos un código de foo / baz, podríamos solicitarlo por su espacio de nombres absoluto:
Si quisiéramos reservar la capacidad de mover eggs.py a otro directorio en el futuro con alguna otra
baz
implementación relativa , podríamos usar una importación relativa como:fuente
Python es un sistema modular
Python no se basa en un sistema de archivos
Para cargar el código de Python de manera confiable, tenga ese código en un módulo y el módulo instalado en la biblioteca de Python.
Los módulos instalados siempre se pueden cargar desde el espacio de nombres de nivel superior con
import <name>
Hay un gran proyecto de muestra disponible oficialmente aquí: https://github.com/pypa/sampleproject
Básicamente, puede tener una estructura de directorios como esta:
.
Asegúrese de declarar su
setuptools.setup()
ensetup.py
,ejemplo oficial: https://github.com/pypa/sampleproject/blob/master/setup.py
En nuestro caso, probablemente queremos exportar
bar.py
yfoo/__init__.py
, mi breve ejemplo:setup.py
.
Ahora podemos instalar nuestro módulo en la biblioteca de Python; con pip, puede instalarlo
the_foo_project
en su biblioteca de python en modo de edición, para que podamos trabajar en él en tiempo real.
Ahora desde cualquier contexto de Python, podemos cargar nuestros módulos y paquetes py_ compartidos
foo_script.py
fuente
pip install --edit foo
, casi siempre dentro de un virtualenv. Casi nunca escribo un módulo que no está destinado a ser instalado. Si no entiendo algo que me gustaría saber.editable
enlaces de huevo y los módulos de python instalados no son exactamente iguales en todos los sentidos; por ejemplo, agregar un nuevo espacio de nombres a un módulo editable se encontrará en su búsqueda de ruta, pero si eso no se exporta en su archivo setup.py, ¡no se empaquetará / instalará!