このディレクトリ構造を想像してみてください。
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
私はmod1
をコーディングしています、そして私はmod2
から何かをインポートする必要があります。どうすればいいですか。
私はfrom ..sub2 import mod2
を試しましたが、「非パッケージでの相対インポートの試行」を受けています。
私はぐるぐる回ったが「sys.path
操作」ハックしか見つけられなかった。きれいな方法はありませんか?
編集:私のすべての__init__.py
は現在空です
Edit2:sub2にはサブパッケージ間で共有されるクラス(sub1
、subX
など)が含まれているのでこれをやろうとしています。
編集3:私が探している振る舞いは PEP 366 で説明されているのと同じです(ありがとうJohn B)
ただ質問に答えるのではなく、誰があなたがすべきことをあなたに伝えたいと思うようです。
問題は、mod1.pyをインタプリタの引数として渡すことによって、モジュールを '__main__'として実行していることです。
相対インポートでは、モジュールの__name__属性を使用して、パッケージ階層内でのそのモジュールの位置を決定します。モジュールの名前にパッケージ情報が含まれていない場合(たとえば '__main__'に設定されている場合)、モジュールが実際にファイルシステム上のどこにあるかにかかわらず、相対インポートはモジュールが最上位モジュールであるかのように解決されます。
Python 2.6では、メインモジュールに関連してモジュールを参照する機能を追加しています。 PEP 366 で変更点が説明されています。
更新:Nick Coghlanによれば、-mスイッチを使用してパッケージ内でモジュールを実行することをお勧めします。
main.py
setup.py
app/ ->
__init__.py
package_a/ ->
__init__.py
module_a.py
package_b/ ->
__init__.py
module_b.py
python main.py
を実行します。main.py
の機能:import app.package_a.module_a
module_a.py
はimport app.package_b.module_b
を行います代わりに2または3が使用することができます:from app.package_a import module_a
PYTHONPATHにapp
がある限り、それは機能します。 main.py
はその場所ならどこでも構いません。
そのため、アプリケーションパッケージ全体とサブパッケージをターゲットシステムのpythonフォルダーにコピー(インストール)するためのsetup.py
を作成し、ターゲットシステムのスクリプトフォルダーにmain.py
を作成します。
これは私のために働く解決策です:
相対インポートをfrom ..sub2 import mod2
として実行し、mod1.py
を実行したい場合はapp
の親ディレクトリに移動し、python -m app.sub1.mod1
としてpython -mスイッチを使用してモジュールを実行します。
この問題が相対インポートで発生する本当の理由は、相対インポートがモジュールの__name__
プロパティを使用することによって機能するためです。モジュールが直接実行されている場合、__name__
は__main__
に設定され、パッケージ構造に関する情報は含まれません。そしてそれが、pythonがrelative import in non-package
エラーについて文句を言う理由です。
そのため、-mスイッチを使用することによって、パッケージ構造情報をpythonに提供し、それを通じて相対インポートを正常に解決できます。
相対インポートをしている間に、私は何度もこの問題に遭遇しました。そして、前の答えをすべて読んだ後でも、すべてのファイルに定型コードを入れる必要なしに、どうやってそれを解決するのかをきちんと理解することができませんでした。 (@ncoghlanと@XiongChiamiovのおかげで、いくつかのコメントは本当に役に立ちましたが)
これが相対輸入問題と戦っている誰かに役立つことを願っています、なぜならPEPを通過するのは本当に楽しいことではないからです。
"Guidoは、パッケージ内のスクリプトの実行をアンチパターンと見なしています"(拒否されました PEP-3122 )
私は解決策を見つけることに努力し、ここでStack Overflowの関連記事を読み、「もっと良い方法があるはずです!」と自分自身に言っているのでとても時間を費やしました。ないようです。
これは100%解決されます。
App/main.pyにsettings/local_setting.pyをインポートします。
main.py:
import sys
sys.path.insert(0, "../settings")
try:
from local_settings import *
except ImportError:
print('No Import')
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
このスニペットを使ってパスからモジュールをインポートしています。
例付きnosklo's
回答の説明
注:すべての__init__.py
ファイルは空です。
main.py
app/ ->
__init__.py
package_a/ ->
__init__.py
fun_a.py
package_b/ ->
__init__.py
fun_b.py
def print_a():
print 'This is a function in dir package_a'
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()
from app.package_b import fun_b
fun_b.print_b()
あなたが$ python main.py
を実行するならば、それは戻ります:
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
from app.package_b import fun_b
from app.package_a.fun_a import print_a
を行いますそのため、フォルダpackage_b
内のファイルは、フォルダpackage_a
内のファイルを使用しました。右??
これは残念ながらsys.pathハックですが、それはかなりうまくいきます。
私は別の層でこの問題に遭遇しました:私はすでに指定された名前のモジュールを持っていましたが、それは間違ったモジュールでした。
私がやりたかったのは以下のことでした(私が働いていたモジュールはmodule3でした):
mymodule\
__init__.py
mymodule1\
__init__.py
mymodule1_1
mymodule2\
__init__.py
mymodule2_1
import mymodule.mymodule1.mymodule1_1
私はすでにmymoduleをインストールしていますが、私のインストールでは "mymodule1"は持っていません。
それは私のインストールされているモジュールからインポートしようとしていたので、私はImportErrorを得るでしょう。
Sys.path.appendを実行しようとしましたが、うまくいきませんでした。うまくいったのはsys.path.insert
if __== '__main__':
sys.path.insert(0, '../..')
ハックのようなものですが、すべてうまくいきました。ですから、他のパスを上書きすることを決定したい場合、それを取得するにはsys.path.insert(0、pathname)を使用する必要があります。働くために!これは私にとって非常にイライラする固着点でした、多くの人がsys.pathに "append"関数を使うと言いますが、あなたがすでにモジュールを定義しているならそれはうまくいきません(私はそれが非常に奇妙な振る舞いを見つける)
私の参照のためにこれをここに置いておきましょう。私はそれが良いPythonコードではないことを知っています、しかし私が取り組んでいたプロジェクトのためのスクリプトが必要でした、そして私はscripts
ディレクトリにスクリプトを置きたいと思いました。
import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
@EvgeniSergeevがOPへのコメントで述べているように、任意の場所にある.py
ファイルからコードをインポートすることができます。
import imp
foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()
これは this SO answer から取られます。
http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports をご覧ください。あなたはできる
from .mod1 import stuff
Pythonドキュメント から、
Python 2.5では、
from __future__ import absolute_import
ディレクティブを使用してインポートの動作を絶対インポートに切り替えることができます。この絶対インポートの振る舞いは将来のバージョン(おそらくPython 2.7)ではデフォルトになるでしょう。絶対インポートがデフォルトになると、import string
は常に標準ライブラリのバージョンを見つけます。ユーザーはできるだけ絶対インポートを使用し始めることをお勧めします。そのため、コードにfrom pkg import string
を記述することをお勧めします
John Bが言ったことに加えて、他のものを台無しにする可能性がある__package__
を変更するのではなく、__main__
変数を設定することが役に立つべきであるように思えます。しかし、私がテストすることができる限りでは、それは本来のように完全には機能しません。
私は同じ問題を抱えており、PEP 328も366も問題を完全に解決することはできません。どちらも、結局のところ、私が理解できる範囲でパッケージの先頭をsys.path
に含める必要があるからです。
私はそれらの変数に入るべき文字列をフォーマットする方法を私は見つけられなかったことにも言及すべきです。 "package_head.subfolder.module_name"
ですか、それとも何ですか。
一番上のフォルダに "PYTHONPATH"環境変数を設定する方が簡単だとわかりました。
bash$ export PYTHONPATH=/PATH/TO/APP
その後:
import sub1.func1
#...more import
もちろん、PYTHONPATHは「グローバル」ですが、それでも私にとっては問題ありません。