para - paquetes de python
importar la función local desde un módulo alojado en otro directorio con importaciones relativas en el cuaderno jupyter usando python3 (3)
Tengo una estructura de directorio similar a la siguiente
meta_project
project1
__init__.py
lib
module.py
__init__.py
notebook_folder
notebook.jpynb
Cuando trabajo en
notebook.jpynb
si intento usar una importación relativa para acceder a una función de
function()
en
module.py
con:
from ..project1.lib.module import function
Obtuve el siguiente error
SystemError Traceback (most recent call last)
<ipython-input-7-6393744d93ab> in <module>()
----> 1 from ..project1.lib.module import function
SystemError: Parent module '''' not loaded, cannot perform relative import
¿Hay alguna manera de hacer que esto funcione utilizando importaciones relativas?
Tenga en cuenta que el servidor de notebook se instancia en el nivel del directorio
meta_project
, por lo que debe tener acceso a la información en esos archivos.
Tenga en cuenta, además, que al menos como el proyecto original
project1
no se pensó como un módulo y, por lo tanto, no tiene un archivo
__init__.py
, solo se entiende como un directorio del sistema de archivos.
Si la solución al problema requiere tratarlo como un módulo e incluir un archivo
__init__.py
(incluso uno en blanco) está bien, pero hacerlo no es suficiente para resolver el problema.
Comparto este directorio entre máquinas y las importaciones relativas me permiten usar el mismo código en todas partes, y a menudo uso portátiles para la creación rápida de prototipos, por lo que es poco probable que las sugerencias que implican hackear rutas absolutas sean útiles.
Editar: Esto es diferente a las importaciones relativas en Python 3 , que habla sobre las importaciones relativas en Python 3 en general y, en particular, la ejecución de un script desde un directorio de paquetes. Esto tiene que ver con trabajar en un cuaderno jupyter tratando de llamar a una función en un módulo local en otro directorio que tiene aspectos generales y particulares diferentes.
Hasta ahora, la respuesta aceptada ha funcionado mejor para mí.
Sin embargo, mi preocupación siempre ha sido que existe un escenario probable en el que podría refactorizar el directorio de
notebooks
en subdirectorios, lo que requiere cambiar el
module_path
en cada cuaderno.
Decidí agregar un archivo python dentro de cada directorio de notebook para importar los módulos requeridos.
Por lo tanto, teniendo la siguiente estructura de proyecto:
project
|__notebooks
|__explore
|__ notebook1.ipynb
|__ notebook2.ipynb
|__ project_path.py
|__ explain
|__notebook1.ipynb
|__project_path.py
|__lib
|__ __init__.py
|__ module.py
project_path.py
el archivo
project_path.py
en cada subdirectorio del
notebooks/explore
(
notebooks/explore
y
notebooks/explain
).
Este archivo contiene el código para las importaciones relativas (de @metakermit):
import sys
import os
module_path = os.path.abspath(os.path.join(os.pardir, os.pardir))
if module_path not in sys.path:
sys.path.append(module_path)
De esta manera, solo necesito hacer importaciones relativas dentro del archivo
project_path.py
, y no en los cuadernos.
Los archivos de los cuadernos solo tendrían que importar
project_path
antes de importar
lib
.
Por ejemplo en
0.0-notebook.ipynb
:
import project_path
import lib
La advertencia aquí es que revertir las importaciones no funcionaría. ESTO NO FUNCIONA:
import lib
import project_path
Por lo tanto, se debe tener cuidado durante las importaciones.
Tuve casi el mismo ejemplo que usted en este cuaderno donde quería ilustrar el uso de la función de un módulo adyacente de manera SECA.
Mi solución fue informarle a Python de esa ruta de importación de módulo adicional agregando un fragmento como este al cuaderno:
import os
import sys
module_path = os.path.abspath(os.path.join(''..''))
if module_path not in sys.path:
sys.path.append(module_path)
Esto le permite importar la función deseada desde la jerarquía del módulo:
from project1.lib.module import function
# use the function normally
function(...)
Tenga en cuenta que es necesario agregar archivos
__init__.py
vacíos a
__init__.py
carpetas
project1 /
y
lib /
si aún no los tiene.
Vine aquí buscando las mejores prácticas para abstraer código a submódulos cuando trabajaba en Notebooks. No estoy seguro de que haya una mejor práctica. He estado proponiendo esto.
Una jerarquía de proyecto como tal:
├── ipynb
│ ├── 20170609-Examine_Database_Requirements.ipynb
│ └── 20170609-Initial_Database_Connection.ipynb
└── lib
├── __init__.py
└── postgres.py
Y desde
20170609-Initial_Database_Connection.ipynb
:
In [1]: cd ..
In [2]: from lib.postgres import database_connection
Esto funciona porque, de manera predeterminada, Jupyter Notebook puede analizar el comando
cd
.
Tenga en cuenta que esto no hace uso de la magia de Python Notebook.
Simplemente funciona sin anteponer
%bash
.
Considerando que 99 de cada 100 veces estoy trabajando en Docker usando una de las imágenes del Proyecto Jupyter Docker , la siguiente modificación es idempotente
In [1]: cd /home/jovyan
In [2]: from lib.postgres import database_connection