Używam Python 2.5.
To jest moje drzewo folderów:
ptdraft/
nib.py
simulations/
life/
life.py
(Mam również __init__.py
w każdym folderze, pominięto tutaj ze względu na czytelność)
Jak zaimportować nib
moduł z wnętrza life
modułu? Mam nadzieję, że można to zrobić bez majsterkowania przy sys.path.
Uwaga: Uruchomiony moduł główny znajduje się w ptdraft
folderze.
__init__.py
. S.Lott: Nie wiem, jak to sprawdzić ...sys.path
lubPYTHONPATH
odpowiedzi i sprawdzenie doskonałej odpowiedzi np8 . Tak, to długa lektura. Tak, to wygląda na dużo pracy. Ale to jedyna odpowiedź, która faktycznie rozwiązuje problem poprawnie i czysto.Odpowiedzi:
Wygląda na to, że problem nie jest związany z tym, że moduł znajduje się w katalogu nadrzędnym lub czymkolwiek podobnym.
Musisz dodać katalog zawierający
ptdraft
PYTHONPATHPowiedziałeś, że to
import nib
z tobą działało, co prawdopodobnie oznacza, że dodałeśptdraft
siebie (nie jego rodzica) do PYTHONPATH.źródło
import sys
a następniesys.path.append("..\<parent_folder>")
Możesz użyć importu względnego (python> = 2,5):
(Co nowego w Python 2.5) PEP 328: Import bezwzględny i względny
EDYCJA : dodano kolejną kropkę „.” przejść dwa pakiety
źródło
ValueError: Attempted relative import in non-package
__init__.py
pliku.__init__.py
nie jest jedyną rzeczą, którą musisz zrobić: stackoverflow.com/questions/11536764/…Względne importy (jak w
from .. import mymodule
) działają tylko w pakiecie. Aby zaimportować „mymoduł” znajdujący się w katalogu nadrzędnym bieżącego modułu:edycja :
__file__
atrybut nie zawsze jest podawany. Zamiast używaćos.path.abspath(__file__)
zasugerowałem teraz użycie modułu inspekcji do pobrania nazwy pliku (i ścieżki) bieżącego plikuźródło
sys.path.insert(1, os.path.join(sys.path[0], '..'))
parentdir
, ale w jednej ze ścieżek już określonych wsys.path
, istnieje inny moduł o nazwie „mymodule”. Wstawienieparentdir
jako pierwszego elementusys.path
listy gwarantuje, żeparentdir
zamiast tego moduł zostanie zaimportowany.sys.path.insert(1, os.path.realpath(os.path.pardir))
też działa.Podałem podobną odpowiedź również na pytanie dotyczące importu z opakowań rodzeństwa. Możesz to zobaczyć tutaj .
Rozwiązanie bez
sys.path
włamańPodsumowanie
packaged_stuff
)setup.py
skryptu tworzenia, w którym używasz setuptools.setup () .pip install -e <myproject_folder>
from packaged_stuff.modulename import function_name
Ustawiać
Zakładam taką samą strukturę folderów jak w pytaniu
Dzwonię do
.
folderu głównego, aw moim przypadku znajduje się wC:\tmp\test_imports
.Kroki
1) Dodaj a
setup.py
do folderu głównegoZawartość
setup.py
może być po prostuZasadniczo „każdy”
setup.py
działałby. To tylko minimalny działający przykład.2) Użyj środowiska wirtualnego
Jeśli znasz środowiska wirtualne, aktywuj jedno i przejdź do następnego kroku. Korzystanie ze środowisk wirtualnych nie jest absolutnie wymagane, ale naprawdę pomoże ci w dłuższej perspektywie (jeśli masz więcej niż jeden projekt w toku ..). Najbardziej podstawowe kroki to (uruchom w folderze głównym)
python -m venv venv
. /venv/bin/activate
(Linux) lub./venv/Scripts/activate
(Win)Aby dowiedzieć się więcej na ten temat, po prostu wypróbuj Google „tutorial python virtualenv” lub podobny. Prawdopodobnie nigdy nie potrzebujesz żadnych innych poleceń niż tworzenie, aktywowanie i dezaktywowanie.
Po utworzeniu i aktywacji środowiska wirtualnego konsola powinna podać nazwę środowiska wirtualnego w nawiasie
3) pip zainstaluj swój projekt w stanie edytowalnym
Zainstaluj pakiet najwyższego poziomu
myproject
za pomocąpip
. Sztuką jest użycie-e
flagi podczas instalacji. W ten sposób jest on instalowany w stanie edytowalnym, a wszystkie zmiany dokonane w plikach .py zostaną automatycznie uwzględnione w zainstalowanym pakiecie.W katalogu głównym uruchom
pip install -e .
(zwróć uwagę na kropkę, oznacza „bieżący katalog”)Możesz również zobaczyć, że jest on instalowany przy użyciu
pip freeze
4) Importuj, dodając
mainfolder
do każdego importuW tym przykładzie
mainfolder
byłobyptdraft
. Ma to tę zaletę, że nie spotkasz się z kolizjami nazw z innymi nazwami modułów (z biblioteki standardowej Python lub modułów innych firm).Przykładowe użycie
nib.py
life.py
Uruchamianie life.py
źródło
sys.path
i gdzie kod byłby zwykle instalowany przez użytkowników końcowych. Jest to lepsze niżsys.path
hacki (i można uwzględnić użycie PYTHONPATH w tej kategorii hacków ścieżkowych), ponieważ oznacza to, że kod w trakcie programowania powinien zachowywać się tak samo jak dla innych użytkowników. Natomiast przy korzystaniu z modyfikacji ścieżek instrukcje importu zostałyby rozwiązane w inny sposób.Ścieżki zależnej od systemu operacyjnego można użyć w „ścieżce wyszukiwania modułów” wymienionej w sys.path . Możesz więc łatwo dodać katalog nadrzędny w następujący sposób
Jeśli chcesz dodać katalog rodzic-rodzic,
Działa to zarówno w pythonie 2, jak i 3.
źródło
Jeśli dodanie folderu modułów do PYTHONPATH nie zadziałało, możesz zmodyfikować listę sys.path w swoim programie, w którym interpreter Pythona szuka modułów do zaimportowania, dokumentacja python mówi:
Wiedząc o tym, możesz wykonać następujące czynności w swoim programie:
źródło
/path/to/ptdraft
musiałby zostać poddany edycji. Istnieją rozwiązania, które opracowują bieżący katalog pliku i w ten sposób importują go również z folderu nadrzędnego.Nie wiem wiele o python 2.
W python 3 folder macierzysty można dodać w następujący sposób:
... a następnie można z niego importować moduły
źródło
'..'
prowadzi do katalogu z danym modułem.Oto prosta odpowiedź, dzięki czemu można zobaczyć, jak to działa, małe i wieloplatformowe.
Używa tylko wbudowanych modułów (
os
,sys
iinspect
), więc powinno działaćna dowolnym systemie operacyjnym (OS), ponieważ Python jest do tego przeznaczony.
Krótszy kod odpowiedzi - mniej wierszy i zmiennych
W przypadku mniejszej liczby linii zamień drugą linię na
import os.path as path, sys, inspect
,dodaj
inspect.
na początkugetsourcefile
(linia 3) i usuń pierwszą linię.- importuje to jednak cały moduł, więc może potrzebować więcej czasu, pamięci i zasobów.
Kod mojej odpowiedzi ( dłuższa wersja )
Wykorzystuje przykład z odpowiedzi Przepełnienie stosu Jak uzyskać ścieżkę prądu
wykonywanego pliku w Pythonie? znaleźć źródło (nazwę pliku) działającego kodu za pomocą wbudowanego narzędzia.
Mój kod dodaje ścieżkę do pliku
sys.path
, na liście ścieżki Pythona, ponieważ pozwala to Pythona do modułów importu z tego folderu.
Po zaimportowaniu modułu do kodu dobrym pomysłem jest uruchomienie
sys.path.pop(0)
w nowym wierszu,gdy dodany folder ma moduł o takiej samej nazwie jak inny importowany moduł
później w programie. Musisz usunąć element listy dodany przed importem, a nie inne ścieżki.
Jeśli Twój program nie importuje innych modułów, nie można bezpiecznie usunąć ścieżki do pliku, ponieważ
po zakończeniu programu (lub zrestartowaniu powłoki Python) wszelkie zmiany wprowadzone w
sys.path
zniknięcia.Uwagi na temat zmiennej nazwy pliku
Moja odpowiedź nie korzysta ze
__file__
zmiennej, aby uzyskać ścieżkę do pliku / nazwę uruchomionegokodu, ponieważ użytkownicy tutaj często opisywali ją jako niewiarygodną . Nie należy używać go
do importowania modułów z folderu nadrzędnego w programach używanych przez inne osoby.
Kilka przykładów, gdzie nie działa (cytat z tym pytanie przepełnienie stosu):
• nie można go znaleźć na niektórych platformach • czasem nie jest to pełna ścieżka do pliku
źródło
sys.path.pop(0)
zaraz po zaimportowaniu pożądanego modułu. Jednak kolejny import nadal trafiał do tej lokalizacji. Na przykład, mamapp/config
,app/tools
iapp/submodule/config
. Zsubmodule
, wstawiamapp/
importowaćtools
, a następnie usuwamapp/
i próbuję importowaćconfig
, ale dostajęapp/config
zamiastapp/submodule/config
.tools
importów był również importowanyconfig
z katalogu macierzystego. Więc kiedy później spróbowałem zrobić to wsys.path.pop(0); import config
środkusubmodule
, spodziewając się, że dostanęapp/submodule/config
, faktycznie dostałemapp/config
. Najwyraźniej Python zwraca buforowaną wersję modułu o tej samej nazwie zamiast faktycznie sprawdzaćsys.path
moduł pasujący do tej nazwy.sys.path
w tym przypadku był poprawnie zmieniany, Python po prostu go nie sprawdzał, ponieważ moduł o tej samej nazwie został już załadowany.sys.modules
... sys.modules można zapisywać. Usunięcie klucza spowoduje unieważnienie wpisu pamięci podręcznej dla nazwanego modułu, powodując, że Python zacznie ponownie wyszukiwać przy następnym imporcie. ... Uważaj jednak, jakbyś zachowywał odwołanie do obiektu modułu, unieważnił pamięć podręczną, a następnie ponownie zaimportował, oba obiekty będą różne. Natomiastimportlib.reload()
ponownie użyje i ponownie zainicjuje zawartość modułu ...os.path.realpath(getsourcefile(lambda:0) + "/../..")
. Otrzyma bieżący plik źródłowy z dołączonymi dwoma symbolami katalogu nadrzędnego. Nie użyłem,os.path.sep
jakgetsourcefile
to zwraca ciąg, używając/
nawet w systemie Windows.realpath
zajmie się usunięciem dwóch pozycji katalogu z pełnej ścieżki (w tym przypadku nazwa pliku, a następnie bieżący katalog), co daje katalog nadrzędny.Oto bardziej ogólne rozwiązanie, które obejmuje katalog nadrzędny w sys.path (działa dla mnie):
źródło
import os, sys\n sys.path.insert(0,os.path.pardir)
to samo, ale sorther :) (brak komentarzy wos.path.pardir
, nie dostanieszsys.path.insert()
__file__
zmienną, która może być zawodna (nie zawsze pełna ścieżka pliku, nie działa w każdym systemie operacyjnym itp.), Jak często wspominali użytkownicy StackOverflow. Zmiana odpowiedzi na nieuwzględniającą spowoduje mniej problemów i będzie bardziej kompatybilna krzyżowo. Aby uzyskać więcej informacji, zobacz stackoverflow.com/a/33532002/3787376 .Odkryłem, że następujący sposób działa w przypadku importowania pakietu z katalogu nadrzędnego skryptu. W tym przykładzie chciałbym zaimportować funkcje
env.py
zapp.db
pakietu.źródło
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
sys.path
wcale nie jest dobrym pomysłem. W przeglądarce musi być jakiś sposób ( np ,PYTHONPATH
) do biblioteki, aby były dostępne do innego kodu (albo tak naprawdę nie jest to biblioteka); po prostu używaj tego cały czas!Wyżej wymienione rozwiązania są również w porządku. Innym rozwiązaniem tego problemu jest
Jeśli chcesz zaimportować cokolwiek z katalogu najwyższego poziomu. Następnie,
Ponadto, jeśli chcesz zaimportować dowolny moduł z katalogu nadrzędnego. Następnie,
Ponadto, jeśli chcesz zaimportować dowolny moduł z katalogu nadrzędnego. Następnie,
W ten sposób możesz zaimportować dowolną metodę, jeśli chcesz.
źródło
sys.path.append
powyższe hacki i nie mogę zaimportować mojej biblioteki lib w ten sposób. Właśnie to najpierw próbowałem zrobić, zanim zacząłem google :) Ok, to było toValueError: attempted relative import beyond top-level package
Dla mnie najkrótszym i moim ulubionym narzędziem dostępu do katalogu nadrzędnego jest:
lub:
os.getcwd () zwraca nazwę bieżącego katalogu roboczego, os.path.dirname (nazwa_katalogu) zwraca nazwę katalogu dla przekazanego katalogu.
Moim zdaniem architektura projektu Python powinna być wykonana w taki sposób, aby żaden moduł z katalogu potomnego nie używał żadnego modułu z katalogu nadrzędnego. Jeśli coś takiego się zdarzy, warto przemyśleć drzewo projektu.
Innym sposobem jest dodanie katalogu nadrzędnego do systemowej zmiennej środowiskowej PYTHONPATH.
źródło
W notatniku Jupyter
Tak długo, jak pracujesz w notatniku Jupyter, to krótkie rozwiązanie może być przydatne:
Działa nawet bez
__init__.py
pliku.Testowałem to z Anaconda3 na Linuxie i Windowsie 7.
źródło
%cd -
po imporcie nie ma sensu , więc bieżący katalog notebooka pozostaje niezmieniony.import sys sys.path.append('../')
źródło
Gdy nie znajduje się w środowisku pakietu z
__init__.py
plikami, biblioteka pathlib (zawarta w> = Python 3.4) sprawia, że dołączenie ścieżki katalogu nadrzędnego do PYTHONPATH jest bardzo zwięzłe i intuicyjne:źródło
taki sam styl jak w poprzedniej odpowiedzi - ale w mniejszej liczbie wierszy: P
plik zwraca lokalizację, w której pracujesz
źródło
Praca z bibliotekami. Utwórz bibliotekę o nazwie nib, zainstaluj ją za pomocą setup.py, pozwól jej znajdować się w pakietach witryn, a twoje problemy zostaną rozwiązane. Nie musisz pakować wszystkiego, co robisz w jednym pakiecie. Rozbij to na kawałki.
źródło
site-packages
każdym razem, gdy uruchamiają go na innym komputerze.W systemie Linux możesz utworzyć miękkie łącze z folderu „life” do pliku nib.py. Następnie możesz po prostu zaimportować go w następujący sposób:
źródło