Jak zrobić import względny w Pythonie?
Wyobraź sobie strukturę katalogów:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
Koduję mod1
i muszę coś zaimportować z mod2
. Jak mam to zrobić?
Próbowałem from ..sub2 import mod2
, ale otrzymuję "Attempted relative import in non-package".
Wygooglowałem, ale znalazłem tylko hacki "sys.path
manipulacja". Nie ma czystego sposobu?
Edit: wszystkie moje __init__.py
są obecnie puste
Edit2: próbuję to zrobić, ponieważ sub2 zawiera klasy, które są współdzielone między pod pakietami (sub1
, subX
, itd.).
Edit3: zachowanie którego szukam jest takie samo jak opisane w PEP 366 (Dzięki John B)
16 answers
Wydaje się, że każdy chce ci powiedzieć, co powinieneś robić, a nie tylko odpowiadać na pytanie.
Problem polega na tym, że uruchamiasz moduł jako '_ _ main__ ' przekazując mod1.py jako argument dla tłumacza.
From PEP 328:
Import względny używa atrybutu __Nazwa__ modułu do określenia pozycji tego modułu w hierarchii pakietów. Jeśli nazwa modułu nie zawiera żadnych informacji o pakiecie (np. jest ustawiona na ' _ _ main__') następnie względne importy są rozwiązywane tak, jakby moduł był modułem najwyższego poziomu, niezależnie od tego, gdzie moduł znajduje się w systemie plików.
W Pythonie 2.6 dodają możliwość odwoływania się do modułów względem głównego modułu. PEP 366 opisuje zmianę.
Update: według Nicka Coghlana, zalecaną alternatywą jest uruchomienie modułu wewnątrz pakietu za pomocą przełącznika-M.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-07 15:25:46
main.py
setup.py
app/ ->
__init__.py
package_a/ ->
__init__.py
module_a.py
package_b/ ->
__init__.py
module_b.py
- biegniesz
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 można użyć: from app.package_a import module_a
To będzie działać tak długo, jak masz app
w swojej ścieżce PYTHONPATH. Więc może być wszędzie.
Więc piszesz setup.py
aby skopiować (zainstalować) cały pakiet aplikacji i podpakiety do folderów Pythona systemu docelowego i main.py
do folderów skryptów systemu docelowego.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-21 12:42:11
Oto rozwiązanie, które działa dla mnie:
Robię import względny jako from ..sub2 import mod2
następnie, jeśli chcę uruchomić mod1.py
, idę do katalogu nadrzędnego app
i uruchamiam moduł używając przełącznika python-m jako python -m app.sub1.mod1
.
Prawdziwym powodem, dla którego ten problem występuje przy relatywnym imporcie, jest to, że relatywny import działa przyjmując właściwość __name__
modułu. Jeśli moduł jest uruchamiany bezpośrednio, to __name__
jest ustawione na __main__
i nie zawiera żadnych informacji o pakiecie struktura. I dlatego python narzeka na błąd relative import in non-package
.
Tak więc, używając przełącznika-m, przekazujesz pythonowi informacje o strukturze pakietów, za pomocą których może on pomyślnie rozwiązać względny import.
Napotkałem ten problem wiele razy podczas względnego importu. I, po przeczytaniu wszystkich poprzednich odpowiedzi, nadal nie byłem w stanie dowiedzieć się, jak go rozwiązać, w czysty sposób, bez konieczności umieszczania kodu boilerplate we wszystkich plikach. (Choć niektóre z komentarze były naprawdę pomocne, dzięki @ ncoghlan i @XiongChiamiov)
Mam nadzieję, że pomoże to komuś, kto walczy z problemem względnego importu, ponieważ przechodzenie przez PEP nie jest naprawdę zabawne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-17 07:43:34
"Guido postrzega uruchamianie skryptów w pakiecie jako anty-wzorzec" (odrzucony PEP-3122)
Spędziłem tyle czasu próbując znaleźć rozwiązanie, czytając powiązane posty tutaj na Stack Overflow i mówiąc sobie "musi być lepszy sposób!". Wygląda na to, że nie ma.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-26 20:14:16
def import_path(fullpath):
"""
Import a file with full path specification. Allows one to
import from anywhere, something __import__ does not do.
"""
path, filename = os.path.split(fullpath)
filename, ext = os.path.splitext(filename)
sys.path.append(path)
module = __import__(filename)
reload(module) # Might be out of date
del sys.path[-1]
return module
Używam tego fragmentu do importowania modułów ze ścieżek, mam nadzieję, że to pomoże
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-22 19:18:28
To jest rozwiązane w 100%:
- app/
- main.py
- Ustawienia/
- local_setings.py
Import settings/local_setting.py w app/main.py:
Main.py:
import sys
sys.path.insert(0, "../settings")
try:
from local_settings import *
except ImportError:
print('No Import')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-05 00:28:07
Wyjaśnienie odpowiedzi nosklo's
z przykładami
uwaga: wszystkie pliki __init__.py
są puste.
main.py
app/ ->
__init__.py
package_a/ ->
__init__.py
fun_a.py
package_b/ ->
__init__.py
fun_b.py
App/package_a/fun_a.py
def print_a():
print 'This is a function in dir package_a'
App/package_b/fun_b.py
from app.package_a.fun_a import print_a
def print_b():
print 'This is a function in dir package_b'
print 'going to call a function in dir package_a'
print '-'*30
print_a()
Main.py
from app.package_b import fun_b
fun_b.print_b()
Jeśli uruchomisz $ python main.py
zwraca:
This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
- main.py czy:
from app.package_b import fun_b
- fun_b.py czy
from app.package_a.fun_a import print_a
Więc plik w folderze package_b
używany plik w folderze package_a
, czyli to, co chcesz. Prawda??
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-08 03:19:42
To jest niestety sys.Path hack, ale działa całkiem dobrze.
Napotkałem ten problem z inną warstwą: miałem już moduł o podanej nazwie, ale był to zły moduł.
To, co chciałem zrobić ,było następujące (moduł, z którego pracowałem, to module3):
mymodule\
__init__.py
mymodule1\
__init__.py
mymodule1_1
mymodule2\
__init__.py
mymodule2_1
import mymodule.mymodule1.mymodule1_1
Zauważ, że mam już zainstalowany mymodule, ale w mojej instalacji nie mam "mymodule1"
I dostałbym ImportError, ponieważ próbował zaimportować z mojego zainstalowane moduły.
Próbowałem zrobić sys./ align = "left" / / align = "left" / To, co działało, to sys./ align = "left" / insertif __name__ == '__main__':
sys.path.insert(0, '../..')
To rodzaj włamania, ale wszystko działa! Pamiętaj więc, że jeśli chcesz, aby twoja decyzja nadpisała inne ścieżki , musisz użyć sys./ align = "left" / insert (0, pathname) to get it to work! To był bardzo frustrujący punkt dla mnie, allot ludzi mówią, aby użyć funkcji "dołącz" do sys.ścieżka, ale to nie działa, jeśli już masz moduł zdefiniowany (uważam to za bardzo dziwne zachowanie)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-05 17:10:18
Pozwól, że umieszczę to tutaj dla własnego odniesienia. Wiem, że nie jest to dobry Kod Pythona, ale potrzebowałem skryptu do projektu, nad którym pracowałem i chciałem umieścić skrypt w katalogu scripts
.
import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-07 04:26:52
Jak pisze @EvgeniSergeev w komentarzach do OP, możesz zaimportować kod z pliku .py
W dowolnej lokalizacji za pomocą:
import imp
foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()
To jest wzięte z to więc odpowiedz .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:11
Spójrz na http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports . You could do
from .mod1 import stuff
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-25 09:39:50
From Python doc ,
W Pythonie 2.5 można zmienić zachowanie importu na import bezwzględny za pomocą dyrektywy
from __future__ import absolute_import
. To zachowanie importu bezwzględnego stanie się domyślne w przyszłej wersji (prawdopodobnie Python 2.7). Gdy import bezwzględny jest domyślny,import string
zawsze znajdzie wersję biblioteki standardowej. Sugeruje się, że użytkownicy powinni zacząć używać importu bezwzględnego jak najwięcej, więc lepiej jest zacząć pisaćfrom pkg import string
w kodzie
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-26 19:44:28
Znalazłem, że łatwiej jest ustawić zmienną środowiska "PYTHONPATH"w górnym folderze:
bash$ export PYTHONPATH=/PATH/TO/APP
Wtedy:
import sub1.func1
#...more import
Oczywiście, PYTHONPATH jest "globalny", ale to jeszcze nie przysporzyło mi kłopotów.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-17 09:20:09
Poza tym, co powiedział John B, wydaje się, że ustawienie zmiennej __package__
powinno pomóc, zamiast zmieniać __main__
, co może zepsuć inne rzeczy. Ale o ile mogę przetestować, to nie działa całkowicie tak, jak powinno.
Mam ten sam problem i ani PEP 328 ani 366 nie rozwiązują problemu całkowicie, ponieważ oba, pod koniec dnia, muszą być włączone do pakietu sys.path
, o ile mogę zrozumieć.
Powinienem również wspomnieć, że nie znalazłem, jak sformatować string, który powinien przejść do tych zmiennych. To jest "package_head.subfolder.module_name"
czy co?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-22 04:35:16
Załóżmy, że biegniesz na najwyższym poziomie, a następnie w mod1
Użyj:
import sub2.mod2
Zamiast
from ..sub2 import mod2
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-29 08:33:02
Myślę, że to, co musisz sobie zadać, to:
- Dlaczego muszę to zrobić?
- czy separacja pakietów jest dobra?
app/
__init__.py
sub1/
__init__.py
mod1.py
sub12/
__init__.py
mod2.py
Wtedy wystarczy:
from sub12 import mod2
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-26 20:47:11