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.

51
demandé sur Community 2015-12-27 10:14:20

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à.

77
répondu metakermit 2016-10-27 08:18:00

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
6
répondu Joshua Cook 2018-01-09 18:11:57

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.

2
répondu Gerges Dib 2018-06-25 17:29:33