2015-12-27 9 views
36

ich eine Verzeichnisstruktur ähnlich die folgendenImport lokale Funktion von einem Modul in einem anderen Verzeichnis mit relativ Importen in jupyter Notebook untergebracht mit python3

habe
meta_project 
    project1 
     __init__.py 
     lib 
      module.py 
      __init__.py 
    notebook_folder 
     notebook.jpynb 

Wenn in notebook.jpynb arbeiten, wenn ich versuche, einen relativ Import zu verwenden, um eine Funktion zugreifen function() in module.py mit:

from ..project1.lib.module import function 

ich folgende Fehlermeldung

erhalten
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 

Gibt es eine Möglichkeit, dies mit relativen Importen zu erreichen?

Hinweis: Der Notebook-Server wird auf der Ebene des Verzeichnisses meta_project instanziiert, sodass er Zugriff auf die Informationen in diesen Dateien haben sollte.

Hinweis, auch, dass mindestens wie ursprünglich vorgesehen project1 wurde nicht als ein Modul gedacht und daher keine __init__.py Datei hat, war es nur als Dateisystem-Verzeichnis gemeint. Wenn die Lösung für das Problem erfordert, es als ein Modul zu behandeln und eine __init__.py Datei (auch eine leere) enthält, ist das in Ordnung, aber dies zu tun ist nicht genug, um das Problem zu lösen.

Ich teile dieses Verzeichnis zwischen Maschinen und relative Importe erlauben mir, den gleichen Code überall zu verwenden, & Ich benutze oft Notebooks für schnelles Prototyping, so dass Vorschläge, die absolute Pfade hacken absolut unwahrscheinlich sind hilfreich.


Edit: Dies ist anders als Relative imports in Python 3, die über relative Einfuhren in Python 3 im Allgemeinen spricht und - insbesondere - ein Skript aus einem Paketverzeichnis ausgeführt wird. Dies hat damit zu tun, dass man in einem jupiterartigen Notizbuch arbeitet, das versucht, eine Funktion in einem lokalen Modul in einem anderen Verzeichnis aufzurufen, das sowohl verschiedene allgemeine als auch bestimmte Aspekte aufweist.

+1

ist es '__init__' Dateien in Ihrem Paket-Verzeichnis? –

+0

Ja, im Verzeichnis 'lib'. – mpacer

+0

Bitte erwähnen Sie es in Ihrer Verzeichnisstruktur in Ihrer Frage –

Antwort

52

Ich hatte fast das gleiche Beispiel wie Sie in this notebook, wo ich die Verwendung der Funktion eines benachbarten Moduls in einer DRY-Weise veranschaulichen wollte.

war meine Lösung Python dieses Zusatzmodul Importpfad zu sagen, durch einen Ausschnitt wie diese an das Notebook hinzufügen:

import os 
import sys 
module_path = os.path.abspath(os.path.join('..')) 
if module_path not in sys.path: 
    sys.path.append(module_path) 

Auf diese Weise können Sie die gewünschte Funktion aus der Modulhierarchie importieren:

from project1.lib.module import function 
# use the function normally 
function(...) 

Beachten Sie, dass es notwendig ist, leer __init__.py Dateien project1/ und lib/ Ordner hinzufügen, wenn Sie sie nicht alrea dy.

+4

Das löst das Problem, ein Paket mit mehr oder weniger einem relativen Ort, aber nur indirekt importieren zu können . Zufällig weiß ich, dass Matthias Bussonier (@matt auf SE) und Yuvi Panda (@yuvi auf SE) https://github.com/ipython/ipynb entwickeln, die dies direkter angehen (z. B. durch Zulassen von relativen Importen unter Verwendung des Standards) Syntax, sobald das Paket importiert wurde). Ich akzeptiere deine Antwort für den Moment, und wenn ihre Lösung vollständig für andere verfügbar ist, werde ich wahrscheinlich entweder eine Antwort schreiben, wie man sie benutzt, oder einen von ihnen bitten, dies zu tun. – mpacer

+0

danke für das Hinweis auf die leere __init__.py Ich bin ein Python-Anfänger und hatte Probleme, meine Klassen zu importieren. Ich habe Modulnotfundfehler erhalten, das Hinzufügen von leerem __init__.py hat das Problem behoben! –

3

Hier kam die Suche nach Best Practices beim Abstrahieren von Code zu Submodulen bei der Arbeit in Notebooks. Ich bin mir nicht sicher, ob es eine Best Practice gibt. Ich habe dies vorgeschlagen.

Eine Projekthierarchie als solche:

├── ipynb 
│   ├── 20170609-Examine_Database_Requirements.ipynb 
│   └── 20170609-Initial_Database_Connection.ipynb 
└── lib 
    ├── __init__.py 
    └── postgres.py 

Und von 20170609-Initial_Database_Connection.ipynb:

In [1]: cd .. 

    In [2]: from lib.postgres import database_connection 

Dies funktioniert, da standardmäßig die Jupyter Notebook den cd Befehl analysieren kann. Beachten Sie, dass dies keine Magie von Python Notebook verwendet. Es funktioniert einfach ohne vorhergehende %bash.

Bedenkt man, dass in 99 von 100 I in Docker arbeitete eine der Project Jupyter Docker images verwenden, die folgende Änderung ist Idempotent

In [1]: cd /home/jovyan 

    In [2]: from lib.postgres import database_connection 
+0

Danke. Wirklich schrecklich die Beschränkungen dieser relativen Importe. – Michael

+0

Ich benutze auch 'chdir' anstelle des Hinzufügens zum Pfad, da ich beide daran interessiert bin, aus dem Hauptrepo zu importieren sowie mit einigen Dateien dort zu interagieren. – TheGrimmScientist

+0

Leider ist das am meisten gehackt was ich in Python mache. Aber ich kann keine bessere Lösung finden. – TheGrimmScientist