Mam strukturę katalogów podobną do poniższej
meta_project
project1
__init__.py
lib
module.py
__init__.py
notebook_folder
notebook.jpynb
Podczas pracy w programie, notebook.jpynb
jeśli spróbuję użyć importu względnego, aby uzyskać dostęp do funkcji function()
w module.py
:
from ..project1.lib.module import function
Otrzymuję następujący błąd:
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
Czy jest jakiś sposób, aby to działało przy użyciu importu względnego?
Należy zauważyć, że serwer notebooków jest tworzony na poziomie meta_project
katalogu, więc powinien mieć dostęp do informacji w tych plikach.
Zauważ również, że przynajmniej tak jak pierwotnie zamierzano, project1
nie był uważany za moduł i dlatego nie ma __init__.py
pliku, miał po prostu służyć jako katalog systemu plików. Jeśli rozwiązanie problemu wymaga potraktowania go jako modułu i dołączenia __init__.py
pliku (nawet pustego), to jest w porządku, ale nie wystarczy, aby rozwiązać problem.
Dzielę ten katalog między maszyny, a względne importy pozwalają mi używać tego samego kodu wszędzie i często używam notebooków do szybkiego prototypowania, więc sugestie, które obejmują hakowanie razem bezwzględnych ścieżek, raczej nie będą pomocne.
Edycja: W przeciwieństwie do importu względnego w Pythonie 3 , który ogólnie mówi o imporcie względnym w Pythonie 3, a zwłaszcza o uruchamianiu skryptu z katalogu pakietu. Ma to związek z pracą w notebooku jupyter, próbując wywołać funkcję w module lokalnym w innym katalogu, która ma różne aspekty ogólne i szczegółowe.
__init__
w katalogu z pakietami są jakieś pliki?lib
katalogu.Odpowiedzi:
Miałem prawie taki sam przykład jak ty w tym notatniku, w którym chciałem zilustrować użycie funkcji sąsiedniego modułu w sposób SUCHY.
Moim rozwiązaniem było poinformowanie Pythona o tej dodatkowej ścieżce importu modułu przez dodanie fragmentu takiego jak ten do notatnika:
Pozwala to na zaimportowanie żądanej funkcji z hierarchii modułów:
Pamiętaj, że konieczne jest dodanie pustych
__init__.py
plików do folderów project1 / i lib /, jeśli jeszcze ich nie masz.źródło
Przyszedłem tutaj, szukając najlepszych praktyk w zakresie wyodrębniania kodu do modułów podrzędnych podczas pracy w notatnikach. Nie jestem pewien, czy istnieje najlepsza praktyka. Ja to proponowałem.
Hierarchia projektu jako taka:
I od
20170609-Initial_Database_Connection.ipynb
:Działa to, ponieważ domyślnie notatnik Jupyter może przeanalizować
cd
polecenie. Zauważ, że nie wykorzystuje to magii Python Notebook. Po prostu działa bez poprzedzania%bash
.Biorąc pod uwagę, że 99 razy na 100 pracuję w Dockerze przy użyciu jednego z obrazów Project Jupyter Docker , następująca modyfikacja jest idempotentna
źródło
chdir
zamiast dodawać do ścieżki, ponieważ jestem zainteresowany importowaniem z głównego repozytorium, a także łączeniem się z niektórymi plikami tam.if os.path.isdir('../lib/'): os.chdir('../lib')
:; lub lepiej, używaj../lib/db/
z twoimpostgres.py
, aby przypadkowo nie zmieniać katalogu do wyższego katalogu zawierającego również innylib
.cd ..
dwukrotnie.Jak dotąd przyjęta odpowiedź działa najlepiej dla mnie. Jednak zawsze martwiłem się, że istnieje prawdopodobny scenariusz, w którym mógłbym
notebooks
zmienić katalog na podkatalogi, wymagając zmianymodule_path
w każdym notatniku. Zdecydowałem się dodać plik Pythona w każdym katalogu notebooka, aby zaimportować wymagane moduły.Zatem mając następującą strukturę projektu:
Dodałem plik
project_path.py
w każdym podkatalogu notatnika (notebooks/explore
inotebooks/explain
). Ten plik zawiera kod do importu względnego (z @metakermit):W ten sposób wystarczy dokonać względnego importu w
project_path.py
pliku, a nie w notatnikach. Pliki notatników musiałyby wtedy po prostu zaimportowaćproject_path
przed zaimportowaniemlib
. Na przykład w0.0-notebook.ipynb
:Zastrzeżenie polega na tym, że cofanie importu nie zadziała. TO NIE DZIAŁA:
Dlatego należy zachować ostrożność podczas importu.
źródło
Właśnie znalazłem to ładne rozwiązanie:
Potrzebujesz tylko niektórych funkcji tego pliku
Jeśli wersja Pythona> = 3.3, nie potrzebujesz pliku init.py w folderze
źródło
if ".." not in sys.path: ... sys.path.insert(0,"..")
Samodzielne badanie tego tematu i przeczytanie odpowiedzi polecam korzystanie z biblioteki path.py, ponieważ zapewnia ona menedżera kontekstu do zmiany bieżącego katalogu roboczego.
Masz wtedy coś takiego
Chociaż możesz po prostu pominąć
isdir
stwierdzenie.Tutaj dodam instrukcje drukowania, aby ułatwić śledzenie tego, co się dzieje
które wyprowadza w tym przykładzie (gdzie lib jest w
/home/jovyan/shared/notebooks/by-team/data-vis/demos/lib
):Ponieważ rozwiązanie korzysta z menedżera kontekstu, masz gwarancję powrotu do poprzedniego katalogu roboczego, bez względu na stan jądra przed komórką i bez względu na to, jakie wyjątki są zgłaszane, importując kod biblioteki.
źródło
Oto moje 2 centy:
import sys
odwzoruj ścieżkę, w której znajduje się plik modułu. W moim przypadku był to pulpit
sys.path.append („/ Users / John / Desktop”)
Albo zaimportuj cały moduł mapowania, ALE wtedy musisz użyć .notation, aby zmapować klasy, takie jak mapping.
import mapping # mapping.py to nazwa mojego pliku modułu
shipit = mapping.Shipment () #Shipment to nazwa klasy, której muszę użyć w module mapowania
Lub zaimportuj określoną klasę z modułu mapowania
z mapowania import Mapping
shipit = Shipment () #Teraz nie musisz używać .notacji
źródło
Odkryłem, że python-dotenv dość skutecznie pomaga rozwiązać ten problem. W końcu struktura Twojego projektu nieco się zmienia, ale kod w Twoim notatniku jest nieco prostszy i spójny we wszystkich notatnikach.
W swoim projekcie zrób małą instalację.
Następnie projekt zmienia się na:
Na koniec import zmienia się na:
+1 dla tego pakietu oznacza, że Twoje notatniki mogą być głębokie na kilka katalogów. python-dotenv znajdzie najbliższy w katalogu nadrzędnym i użyje go. +2 dla tego podejścia oznacza, że jupyter ładuje zmienne środowiskowe z pliku .env podczas uruchamiania. Double whammy.
źródło