web-dev-qa-db-ja.com

Pythonモジュールで相対インポートまたは絶対インポートを適切に使用するにはどうすればよいですか?

Pythonでの相対インポートの使用には1つの欠点があります。例外が発生するため、モジュールをスタンドアロンとして実行できなくなります:ValueError: Attempted relative import in non-package

# /test.py: just a sample file importing foo module
import foo
...

# /foo/foo.py:
from . import bar
...
if __name__ == "__main__":
   pass

# /foo/bar.py: a submodule of foo, used by foo.py
from . import foo
...
if __name__ == "__main__":
   pass

すべてを実行できるようにするには、サンプルコードをどのように変更する必要がありますか:test.pyfoo.pyおよびbar.py

python 2.6+(3.xを含む)で動作するソリューションを探しています。

26
sorin

まず、fooはbarとその逆をインポートするため、作成した内容が循環インポートの問題につながることを理解していると思います。追加してみてください

from foo import bar

test.pyに移動すると、失敗することがわかります。動作させるには、例を変更する必要があります。

したがって、あなたが求めているのは、相対インポートが失敗したときに絶対インポートにフォールバックすることです。実際、foo.pyまたはbar.pyをメインモジュールとして実行している場合、他のモジュールはルートレベルにあるだけであり、システム上の別のモジュールと名前を共有しているかどうかは、どちらが選択されるかによって異なります。 sys.pathの順序。通常、現在のディレクトリが最初であるため、ローカルモジュールが利用可能な場合は選択されます。つまり、現在の作業ディレクトリに「os.py」ファイルがある場合は、組み込みファイルの代わりに選択されます。

考えられる提案は次のとおりです。

foo.py

try:
    from . import bar
except ValueError:
    import bar

if __name__ == "__main__":
    pass

bar.py:

if __name__ == "__main__":
    pass

ちなみに、適切な位置からスクリプトを呼び出す方が、通常wayの方が優れています。

python -m foo.bar

おそらく行くための最良の方法です。これ モジュールをスクリプトとして実行します

16
Alan Franzoni

少し異なる方法で「モジュールをスタンドアロンとして実行する」を開始することができます。

の代わりに:

python foo/bar.py

使用する:

python -mfoo.bar

もちろん、foo/__init__.pyファイルが存在する必要があります。

また、foo.pybar.pyの間には循環依存関係があることに注意してください。これは機能しません。私はそれがあなたの例の単なる間違いだと思います。

更新:これをfoo/bar.pyの最初の行として使用することも完全にうまく機能しているようです。

#!/usr/bin/python -mfoo.bar

次に、POSIXシステムでスクリプトを直接実行できます。

22
Jacek Konieczny

相対的なインポートを捨てる:とにかく、パッケージの名前空間をグローバルな名前空間と考える必要があります。

これを美味しくする秘訣は、sys.pathを適切に編集することです。ここにいくつかの考えの糧があります:

#1つ上のディレクトリ
 _ root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__ file __)))
 sys.path.insert(0 、_root_dir)今のところ
1
Edward Z. Yang

各フォルダに__init__.pyが必要です。

相対インポートは、次の場合にのみ機能します。

python test.py

test.pyはfoo.pyをインポートし、foo.pyはtest.py以上のフォルダーから何でも相対的にインポートできます。

あなたはできません:

cd foo
python foo.py
python bar.py

それは決して機能しません。

Sys.path.appendまたはsys.path.insertソリューションを試すことができますが、パスを台無しにすることになり、f = open(filename)で問題が発生します。

1
Dimitris D

「メイン」を別の.pyファイルに入れてみませんか?

0
Nathan Davis