importer une fonction locale à partir d'un module logé dans un autre répertoire avec des importations relatives dans Jupyter notebook en utilisant python3
j'ai une structure de répertoire similaire à la suivante
meta_project
project1
__init__.py
lib
module.py
__init__.py
notebook_folder
notebook.jpynb
en travaillant dans notebook.jpynb
si j'essaie d'utiliser une importation relative pour accéder à une fonction function()
en module.py
avec:
from ..project1.lib.module import function
j'obtiens l'erreur suivante
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
Est-il un moyen d'obtenir ce travail à l'aide relative des importations?
Remarque, l'ordinateur serveur est instancié au niveau de le répertoire meta_project
, il devrait donc avoir accès à l'information contenue dans ces fichiers.
Note, aussi, qu'au moins tel que prévu à l'origine project1
n'a pas été considéré comme un module et n'a donc pas un fichier __init__.py
, il a été simplement conçu comme un répertoire de système de fichiers. Si la solution du problème nécessite de le traiter comme un module et d'inclure un fichier __init__.py
(même vierge), c'est très bien, mais cela ne suffit pas à résoudre le problème.
je partage ce répertoire entre les machines et les importations relatives me permettent d'utiliser le même code partout, et j'utilise souvent des ordinateurs portables pour le prototypage rapide, de sorte que les suggestions qui impliquent le hacking ensemble chemins absolus sont peu susceptibles d'être utiles.
Edit: ce n'est pas comme importations relatives en Python 3 , qui parle des importations relatives en Python 3 en général et – en particulier-l'exécution d'un script à partir d'un répertoire de paquets. Cela a à voir avec le travail dans un carnet jupyter essayant d'appeler une fonction dans un module local dans un autre répertoire qui a à la fois différents aspects généraux et particuliers.
3 réponses
j'ai eu presque le même exemple que vous dans ce carnet où je voulais illustrer L'utilisation de la fonction d'un module adjacent d'une manière sèche.
ma solution a été de dire à Python de ce chemin d'importation de module supplémentaire en ajoutant un morceau comme celui-ci au bloc-notes:
import os
import sys
module_path = os.path.abspath(os.path.join('..'))
if module_path not in sys.path:
sys.path.append(module_path)
cela vous permet d'importer la fonction désirée de la hiérarchie du module:
from project1.lib.module import function
# use the function normally
function(...)
noter que il est nécessaire d'ajouter des fichiers __init__.py
vides aux dossiers project1/ et lib/ si vous ne les avez pas déjà.
est venu ici à la recherche des meilleures pratiques dans l'Abstraction du code à des sous-modules quand on travaille dans des ordinateurs portables. Je ne suis pas sûr qu'il y ait une bonne pratique. Je propose cette.
Une hiérarchie de projet en tant que tel:
├── ipynb
│ ├── 20170609-Examine_Database_Requirements.ipynb
│ └── 20170609-Initial_Database_Connection.ipynb
└── lib
├── __init__.py
└── postgres.py
et de 20170609-Initial_Database_Connection.ipynb
:
In [1]: cd ..
In [2]: from lib.postgres import database_connection
cela fonctionne parce que par défaut le carnet Jupyter peut analyser la commande cd
. Notez que cela ne fait pas usage de la magie de carnet Python. Il fonctionne simplement sans préprogrammation %bash
.
considérant que 99 fois sur 100 je travaille en Docker en utilisant l'une des projet Jupyter images Docker , la modification suivante est idempotent
In [1]: cd /home/jovyan
In [2]: from lib.postgres import database_connection
jusqu'à présent, la réponse acceptée a fonctionné le mieux pour moi. Cependant, ma préoccupation a toujours été qu'il y ait un scénario probable où je pourrais refactionner le répertoire notebooks
en sous-répertoires, exigeant de changer le module_path
dans chaque carnet. J'ai décidé d'ajouter un fichier python dans chaque répertoire notebook pour importer les modules requis.
donc, ayant la structure de projet suivante:
project
|__notebooks
|__explore
|__ notebook1.ipynb
|__ notebook2.ipynb
|__ project_path.py
|__ explain
|__notebook1.ipynb
|__project_path.py
|__lib
|__ __init__.py
|__ module.py
j'ai ajouté le fichier project_path.py
dans chaque sous-répertoire de carnet ( notebooks/explore
et notebooks/explain
). Ce fichier contient le code des importations relatives (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 cette façon, j'ai juste besoin de faire des importations relatives dans le fichier project_path.py
, et pas dans les carnets. Les fichiers notebooks auraient alors juste besoin d'importer project_path
avant d'importer lib
. Par exemple dans 0.0-notebook.ipynb
:
import project_path
import lib
la mise en garde est que inverser les importations ne fonctionnerait pas. CELA NE FONCTIONNE PAS:
import lib
import project_path
il faut donc être prudent lors des importations.