Pythonでの相対パスからのインポート


104

クライアントコード用のフォルダー、サーバーコード用のフォルダー、およびそれらの間で共有されるコード用のフォルダーがあります。

Proj/
    Client/
        Client.py
    Server/
        Server.py
    Common/
        __init__.py
        Common.py

Server.pyとClient.pyからCommon.pyをインポートするにはどうすればよいですか?


回答:


140

EDIT 2014年11月(3年後):

Python 2.6と3.xは、適切な相対インポートをサポートしているので、ハッキングを一切回避できます。この方法を使用すると、絶対インポートではなく相対インポートを取得していることがわかります。「..」は、私の上のディレクトリに移動することを意味します。

from ..Common import Common

警告として、これはパッケージの外側からモジュールとしてpythonを実行する場合にのみ機能します。例えば:

python -m Proj

オリジナルのハッキーな方法

この方法は、パッケージを実際に「インストール」することがない状況でも、依然として一般的に使用されています。たとえば、Djangoユーザーに人気があります。

Common /をsys.pathに追加できます(Pythonが物事をインポートするために調べるパスのリスト):

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

os.path.dirname(__file__) 現在のpythonファイルが置かれているディレクトリが表示されたら、「Common /」ディレクトリに移動して、「Common」モジュールをインポートします。


2
Pythonモジュールのパスを手動で変更しないでください。迅速なハッキングのためにのみ使用される場合があります。通常、distutils、setuptoolsなどを使用してPythonパッケージ管理を学ぶことは、そのような問題を解決するために必要なスキルです。
Sascha Gottfried

1
@SaschaGottfriedは完全に同意しますが、配布可能なパッケージを作成しない場合は、おそらく問題にはなりません。たとえば、Djangoでは、distutilsを使用してアプリを実際にインストールすることはないため、上記の方法は簡単なハックです。しかし、とにかく私は最近私がすることで答えを編集しました。
Dave

32
適切なテクニックについて説教するのではなく、実際の質問に答えてくれてありがとう。相対的なインポートを行うには、十分な理由がたくさんあります。
shrewmouse 2015年

どのようにして複数のレベルに上がるのですか?
jxramos

10
レベルを1つ上げるには、各レベルに追加のドットを使用します。@jxramosの例:from ...myfileに行く../../myfile
WattsInABox

10

おかしなことに、私がちょうど出会った同じ問題、そして私はこの仕事を次の方法で得る:

Linuxコマンドlnと組み合わせると、物事をより簡単にすることができます。

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

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

そして、次のようにsome_stufffile:Proj/Common/Common.pyからyour file:にインポートする場合はProj/Client/Client.py

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

そして、に同じことが当てはまるProj/Server。またのために働く、setup.pyプロセス、 同じ質問はここで議論し、それが役に立てば幸い!


10

相対インポートを行わないでください。

PEP8から:

パッケージ内インポートの相対インポートはお勧めしません。

すべてのコードを1つのスーパーパッケージ(「myapp」など)に配置し、クライアント、サーバー、および共通コードのサブパッケージを使用します。

更新:Python 2.6および3.xは適切な相対インポート(...)をサポートします」。詳細については、Daveの回答を参照してください。


1
' if __name__ == "__main__":'行の後のクライアントとサーバーの最後にコードを追加するとします。つまり、それらをスタンドアロンスクリプトとして使用できるようにする必要があります。それを正しく行う方法は?それはサポートされるべき完全に一般的なユースケースだと思います。なぜそれが推奨されないのですか?
Jabba 2014年

83
「Do n't do it」が「How do I ...」の質問に対する回答として受け入れられていることに驚いています(Rails <g>を除いて)。これを行う理由時々あります。私はDaveの提案に似たソリューションを使用しています。
トムウィルソン

1
@TomWilson:純粋な「やらない」という答えではありません。以下に「これを行う」があります。
のMichałŠrajer

2
誰かがNumpyでみんなに伝えるべきです!彼らは比較的輸入のトンを使用しています!
オースティンA

12
この回答は、Pythonの現在のバージョンには適用されません。引用部分はPEP 8ではもう見つかりません。今日では、「明示的な相対インポートは絶対インポートの受け入れ可能な代替手段です。特に、絶対インポートの使用が不必要に冗長になる複雑なパッケージレイアウトを扱う場合」
moooeeeep

8

相対インポートを行うことは絶対に大丈夫です!ここでは、ほとんど '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

1
しかし、sys.argv [0]が実際にどこを指しているのかを理解した方がよいでしょう-これは(prolly)が、Pythonを起動したときにあったディレクトリではありません。
CarlH

これは、多くの落とし穴がある、迅速なハックです。しかし、問題はさらに良くはありませんでした。
Sascha Gottfried

1
これは明確に書かれていますが、Daveの答えの元のハックは__file__、現在のファイルから適切な関係を取得するために使用されるため、より優れています
John Neuhaus

4

デフォルトのインポート方法は、PYTHONPATHからすでに「相対的」です。PYTHONPATHはデフォルトで、一部のシステムライブラリと元のソースファイルのフォルダーにあります。-mで実行してモジュールを実行すると、現在のディレクトリがPYTHONPATHに追加されます。したがって、プログラムのエントリポイントがProj内にある場合、使用import Common.CommonはServer.pyとClient.pyの両方で機能するはずです。

相対インポートを行わないでください。それはあなたがそれが望むように機能しません。


1
これが本当なら、なぜトップの回答がこれを言わないのですか?これは機能しますか?
匿名
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.