Importowanie ze ścieżki względnej w Pythonie

Odpowiedzi:

142

EDYCJA listopad 2014 (3 lata później):

Python 2.6 i 3.x obsługuje prawidłowe importowanie względne, dzięki czemu można uniknąć robienia czegokolwiek hakerskiego. Dzięki tej metodzie wiesz, że otrzymujesz import względny, a nie bezwzględny . „..” oznacza, przejdź do katalogu nad mną:

from ..Common import Common

Uwaga: zadziała to tylko wtedy, gdy uruchomisz Pythona jako moduł spoza pakietu. Na przykład:

python -m Proj

Oryginalny hacky sposób

Ta metoda jest nadal powszechnie używana w niektórych sytuacjach, w których tak naprawdę nigdy nie „instalujesz” swojego pakietu. Na przykład jest popularny wśród użytkowników Django.

Możesz dodać Common / do swojego sys.path (lista ścieżek, na które Python patrzy, aby importować rzeczy):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) po prostu podaje katalog, w którym znajduje się twój bieżący plik Pythona, a następnie przechodzimy do katalogu „Common /” i importujemy moduł „Common”.

Dave
źródło
2
Nie modyfikuj ręcznie ścieżki modułów Pythona, może to być tylko dla szybkich hacków. Nauka zarządzania pakietami Pythona przy użyciu distutils, setuptools itp. Jest zwykle wymaganą umiejętnością, która rozwiąże takie problemy.
Sascha Gottfried
1
@SaschaGottfried całkowicie się zgadzam, chociaż jeśli nie tworzysz pakietu dystrybucyjnego, prawdopodobnie nie będzie to miało znaczenia. Na przykład w Django nigdy tak naprawdę nie instalujesz swojej aplikacji za pomocą distutils, więc powyższa metoda jest łatwym hackowaniem. Ale w każdym razie zredagowałem odpowiedź, podając, co bym teraz zrobił.
Dave
33
Dziękuję, że odpowiedziałeś na właściwe pytanie, zamiast mówić o właściwej technice. Istnieje wiele dobrych powodów, aby dokonać importu względnego.
shrewmouse
jak przejść o więcej niż jeden poziom?
jxramos,
10
aby przejść o jeden poziom wyżej, użyj dodatkowej kropki na każdym poziomie. @jxramos ex: from ...myfileidzie do../../myfile
WattsInABox
10

Zabawne, ten sam problem, który właśnie spotkałem, i otrzymuję tę pracę w następujący sposób:

łącząc z poleceniem linux ln, możemy bardzo uprościć sprawę:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

A teraz, jeśli chcesz importować some_stuffz pliku: Proj/Common/Common.pydo swojego pliku:, Proj/Client/Client.pytak jak to:

# in Proj/Client/Client.py
from Common.Common import some_stuff

I to samo dotyczy Proj/Server, Działa również dla setup.pyprocesu, to samo pytanie omówione tutaj , mam nadzieję, że pomoże!

jacoolee
źródło
10

Nie rób importu względnego.

Z PEP8 :

Względny import w przypadku importu wewnątrz paczki jest wysoce odradzany.

Umieść cały kod w jednym super pakiecie (np. „Myapp”) i używaj podpakietów dla klienta, serwera i wspólnego kodu.

Aktualizacja:Python 2.6 i 3.x obsługuje prawidłowe importowanie względne (...) ”. Zobacz odpowiedzi Dave'a, aby uzyskać więcej informacji.

Michał Šrajer
źródło
1
Wyobraź sobie, że dodajesz kod na końcu klienta i serwera po if __name__ == "__main__":wierszu „ ”. Oznacza to, że chcesz móc ich używać jako samodzielnych skryptów. Jak to zrobić poprawnie? Myślę, że jest to bardzo powszechny przypadek użycia, który powinien być obsługiwany. Dlaczego jest to odradzane?
Jabba
83
Jestem zaskoczony, że „nie rób tego” jest odpowiedzią dopuszczone do „Jak to zrobić ...” pytanie (dobrze, z wyjątkiem szyn <g>). Nie sporadyczne powodów, aby to zrobić. Używam rozwiązania podobnego do tego, które sugeruje Dave.
Tom Wilson
1
@TomWilson: To nie jest czysta odpowiedź „nie rób tego”. Poniżej znajduje się „zrób to w ten sposób”.
Michał Šrajer
2
Ktoś powinien powiedzieć chłopakom z Numpy! Używają TONY względnego importu!
Austin A,
12
Ta odpowiedź nie ma zastosowania do aktualnych wersji Pythona. Cytowanej części nie ma już w PEP 8. Obecnie brzmi ona następująco: „jawny import względny jest akceptowalną alternatywą dla importu absolutnego, szczególnie w przypadku złożonych układów opakowań, w których użycie importu absolutnego byłoby niepotrzebnie
rozwlekłe
8

Wykonanie względnego importu jest absolutnie OK! Oto, co robi mały 'ol me:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py
Gary Beardsley
źródło
1
Ale lepiej wiedz, gdzie faktycznie wskazuje sys.argv [0] - to (prawdopodobnie) nie jest katalog, w którym byłeś, kiedy uruchamiałeś Pythona.
CarlH,
To szybki hack, z wieloma pułapkami. Ale pytanie nie było nawet lepsze.
Sascha Gottfried
1
To wyraźnie napisane, ale oryginalny hack w odpowiedzi Dave'a jest lepszy, ponieważ używa go __file__do uzyskania właściwej relacji z bieżącego pliku
John Neuhaus
4

Domyślna metoda importu jest już „względna” i pochodzi z PYTHONPATH. PYTHONPATH jest domyślnie przypisywana do niektórych bibliotek systemowych wraz z folderem oryginalnego pliku źródłowego. Jeśli uruchomisz z -m, aby uruchomić moduł, bieżący katalog zostanie dodany do PYTHONPATH. Więc jeśli punkt wejścia twojego programu znajduje się wewnątrz Proj, użyjimport Common.Common powinno działać zarówno wewnątrz Server.py, jak i Client.py.

Nie rób względnego importu. Nie będzie działać tak, jak chcesz.

Jonathan Sternberg
źródło
1
Jeśli to prawda, dlaczego w najpopularniejszych odpowiedziach tego nie ma? Czy to zadziała, czy nie?
Anonimowy