Wyobraź sobie tę strukturę katalogów:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
Koduję mod1
i muszę coś zaimportować mod2
. Jak mam to zrobić?
Próbowałem, from ..sub2 import mod2
ale otrzymuję komunikat „Próba względnego importu w pakiecie innym niż pakiet”.
Przeszukiwałem go, ale znalazłem tylko sys.path
hacki „ manipulacyjne”. Czy nie ma czystego sposobu?
Edycja: wszystkie moje __init__.py
są obecnie puste
Edit2: Staram się to zrobić, ponieważ sub2 zawiera klasy, które są wspólne dla pakietów Sub ( sub1
, subX
etc.).
Edycja3: Zachowanie, którego szukam, jest takie samo, jak opisano w PEP 366 (dzięki John B)
Odpowiedzi:
Wydaje się, że wszyscy chcą powiedzieć ci, co powinieneś robić, a nie tylko odpowiedzieć na pytanie.
Problem polega na tym, że uruchamiasz moduł jako „__main__”, przekazując mod1.py jako argument do interpretera.
Od PEP 328 :
W Pythonie 2.6 dodają możliwość odwoływania się do modułów względem modułu głównego. PEP 366 opisuje zmianę.
Aktualizacja : Według Nicka Coghlana zalecaną alternatywą jest uruchomienie modułu wewnątrz pakietu za pomocą przełącznika -m.
źródło
-m
przełącznika, zamiast bezpośredniego podawania ich nazwy pliku.from sub2 import mod2
. Następnie, aby uruchomić mod1 z poziomu aplikacji, wykonajpython -m sub1.mod1
.Oto rozwiązanie, które działa dla mnie:
Wykonuję import względny jak
from ..sub2 import mod2
i wtedy, jeśli chcę uruchomić,mod1.py
to idę do katalogu nadrzędnegoapp
i uruchamiam moduł za pomocą przełącznika python -m aspython -m app.sub1.mod1
.Prawdziwym powodem, dla którego ten problem występuje w przypadku importu względnego, jest fakt, że import względny działa, przejmując
__name__
właściwość modułu. Jeśli moduł jest uruchamiany bezpośrednio, to__name__
jest ustawiony na__main__
i nie zawiera żadnych informacji o strukturze pakietu. I dlatego python narzeka narelative import in non-package
błąd.Tak więc, używając przełącznika -m, podajesz pythonowi informacje o strukturze pakietu, dzięki którym może on pomyślnie rozwiązać import względny.
Problem ten napotkałem wiele razy podczas importowania względnego. Po przeczytaniu wszystkich poprzednich odpowiedzi nadal nie byłem w stanie wymyślić, jak to rozwiązać, w czysty sposób, bez konieczności umieszczania kodu podstawowego we wszystkich plikach. (Chociaż niektóre komentarze były bardzo pomocne, dzięki @ncoghlan i @XiongChiamiov)
Mam nadzieję, że pomoże to komuś, kto walczy z problemem importu względnego, ponieważ przechodzenie przez PEP nie jest naprawdę zabawne.
źródło
-m
zostało zaprojektowane do rozwiązania.from . import some_module
.python main.py
.main.py
robi:import app.package_a.module_a
module_a.py
robiimport app.package_b.module_b
Alternatywnie 2 lub 3 mogą użyć:
from app.package_a import module_a
Będzie to działać tak długo, jak długo masz
app
w swojej PIĄTCE ŚCIEŻKI.main.py
może być gdziekolwiek.Więc piszesz,
setup.py
aby skopiować (zainstalować) cały pakiet aplikacji i podpakiety do folderów pythonmain.py
systemu docelowego i do folderów skryptów systemu docelowego.źródło
„Guido postrzega uruchamianie skryptów w pakiecie jako anty-wzór” (odrzucony PEP-3122 )
Spędziłem tyle czasu próbując znaleźć rozwiązanie, czytając podobne posty tutaj na Stack Overflow i mówiąc sobie: „musi być lepszy sposób!”. Wygląda na to, że nie ma.
źródło
-m
switch:python -m app.sub1.mod1
lub wywołaćapp.sub1.mod1.main()
ze skryptu najwyższego poziomu (np. wygenerowanego z punktów wejścia setuptools zdefiniowanych w setup.py).Zostało to rozwiązane w 100%:
Zaimportuj ustawienia / local_setting.py do app / main.py:
main.py:
źródło
sys.path.insert(0, "../settings")
a następniefrom local_settings import *
Używam tego fragmentu do importowania modułów ze ścieżek, mam nadzieję, że to pomoże
źródło
wyjaśnienie
nosklo's
odpowiedzi z przykładamiUwaga: wszystkie
__init__.py
pliki są puste.app / package_a / fun_a.py
app / package_b / fun_b.py
main.py
po uruchomieniu
$ python main.py
zwraca:from app.package_b import fun_b
from app.package_a.fun_a import print_a
więc plik w folderze
package_b
używał pliku w folderzepackage_a
, co jest tym, czego chcesz. Dobrze??źródło
Jest to niestety hack sys.path, ale działa całkiem dobrze.
Problem napotkałem na innej warstwie: miałem już moduł o określonej nazwie, ale był to niewłaściwy moduł.
chciałem to zrobić (moduł, z którego pracowałem, to moduł3):
Zauważ, że już zainstalowałem mymoduł, ale w mojej instalacji nie mam „mymoduł1”
i dostałbym błąd ImportError, ponieważ próbował zaimportować z moich zainstalowanych modułów.
Próbowałem zrobić sys.path.append, ale to nie zadziałało. To, co zadziałało, to sys.path.insert
Cóż za hack, ale wszystko działało! Pamiętaj więc, że jeśli chcesz zastąpić inne ścieżki , musisz użyć sys.path.insert (0, nazwa ścieżki), aby działało! To było dla mnie bardzo frustrujące, wiele osób twierdzi, że używa funkcji „append” do sys.path, ale to nie działa, jeśli masz już zdefiniowany moduł (uważam to za bardzo dziwne zachowanie)
źródło
sys.path.append('../')
działa dobrze dla mnie (Python 3.5.2)Pozwól mi po prostu umieścić to tutaj dla własnego odniesienia. Wiem, że to nie jest dobry kod Pythona, ale potrzebowałem skryptu dla projektu, nad którym pracowałem i chciałem umieścić skrypt w
scripts
katalogu.źródło
Jak mówi @EvgeniSergeev w komentarzach do OP, możesz importować kod z
.py
pliku w dowolnym miejscu za pomocą:To pochodzi z tej SO odpowiedzi .
źródło
Spójrz na http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports . Mógłbyś
źródło
Z dokumentu Python ,
źródło
Odkryłem, że łatwiej jest ustawić zmienną środowiska „PYTHONPATH” w górnym folderze:
następnie:
oczywiście PYTHONPATH jest „globalny”, ale nie przysporzył mi jeszcze problemów.
źródło
virtualenv
pozwala to zarządzać wyciągami z importu.Oprócz tego, co powiedział John B, wydaje się, że ustawienie
__package__
zmiennej powinno pomóc, zamiast zmieniać__main__
co mogłoby popsuć inne rzeczy. Ale o ile mogłem przetestować, nie działa tak, jak powinien.Mam ten sam problem i ani PEP 328, ani 366 nie rozwiązują go całkowicie, ponieważ do końca dnia oba wymagają dołączenia głowy pakietu
sys.path
, o ile rozumiem.Powinienem również wspomnieć, że nie znalazłem sposobu na sformatowanie ciągu, który powinien przejść do tych zmiennych. Czy to
"package_head.subfolder.module_name"
czy co?źródło
Musisz dołączyć ścieżkę modułu do
PYTHONPATH
:źródło
sys.path
, ponieważsys.path
zostaje zainicjowane zPYTHONPATH
sys.path
musi być zakodowana na stałe w kodzie źródłowym, w przeciwieństwie do tego,PYTHONPATH
która jest zmienną środowiskową i może być eksportowana.