webdevqa.jp.net

Pythonで相対インポートをするにはどうすればいいですか?

このディレクトリ構造を想像してみてください。

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にはサブパッケージ間で共有されるクラス(sub1subXなど)が含まれているのでこれをやろうとしています。

編集3:私が探している振る舞いは PEP 366 で説明されているのと同じです(ありがとうJohn B)

487
Joril

ただ質問に答えるのではなく、誰があなたがすべきことをあなたに伝えたいと思うようです。

問題は、mod1.pyをインタプリタの引数として渡すことによって、モジュールを '__main__'として実行していることです。

PEP 328から

相対インポートでは、モジュールの__name__属性を使用して、パッケージ階層内でのそのモジュールの位置を決定します。モジュールの名前にパッケージ情報が含まれていない場合(たとえば '__main__'に設定されている場合)、モジュールが実際にファイルシステム上のどこにあるかにかかわらず、相対インポートはモジュールが最上位モジュールであるかのように解決されます。

Python 2.6では、メインモジュールに関連してモジュールを参照する機能を追加しています。 PEP 366 で変更点が説明されています。

更新:Nick Coghlanによれば、-mスイッチを使用してパッケージ内でモジュールを実行することをお勧めします。

306
John B
main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. あなたはpython main.pyを実行します。
  2. main.pyの機能:import app.package_a.module_a
  3. module_a.pyimport app.package_b.module_bを行います

代わりに2または3が使用することができます:from app.package_a import module_a

PYTHONPATHにappがある限り、それは機能します。 main.pyはその場所ならどこでも構いません。

そのため、アプリケーションパッケージ全体とサブパッケージをターゲットシステムのpythonフォルダーにコピー(インストール)するためのsetup.pyを作成し、ターゲットシステムのスクリプトフォルダーにmain.pyを作成します。

116
nosklo

これは私のために働く解決策です:

相対インポートを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を通過するのは本当に楽しいことではないからです。

114
Pankaj

"Guidoは、パッケージ内のスクリプトの実行をアンチパターンと見なしています"(拒否されました PEP-3122

私は解決策を見つけることに努力し、ここでStack Overflowの関連記事を読み、「もっと良い方法があるはずです!」と自分自身に言っているのでとても時間を費やしました。ないようです。

46
lesnik

これは100%解決されます。

  • app /
    • main.py
  • 設定/
    • local_setings.py

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

このスニペットを使ってパスからモジュールをインポートしています。

24
iElectric

例付きnosklo's回答の説明

注:すべての__init__.pyファイルは空です。

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()

あなたが$ 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
  • main.pyは何をしますか:from app.package_b import fun_b
  • fun_b.pyはfrom app.package_a.fun_a import print_aを行います

そのため、フォルダpackage_b内のファイルは、フォルダpackage_a内のファイルを使用しました。右??

21
suhailvs

これは残念ながら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"関数を使うと言いますが、あなたがすでにモジュールを定義しているならそれはうまくいきません(私はそれが非常に奇妙な振る舞いを見つける)

11
Garrett Berg

私の参照のためにこれをここに置いておきましょう。私はそれが良いPythonコードではないことを知っています、しかし私が取り組んでいたプロジェクトのためのスクリプトが必要でした、そして私はscriptsディレクトリにスクリプトを置きたいと思いました。

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
10
milkypostman

@EvgeniSergeevがOPへのコメントで述べているように、任意の場所にある.pyファイルからコードをインポートすることができます。

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

これは this SO answer から取られます。

8
LondonRob

http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports をご覧ください。あなたはできる

from .mod1 import stuff
4
mossplix

Pythonドキュメント から、

Python 2.5では、from __future__ import absolute_importディレクティブを使用してインポートの動作を絶対インポートに切り替えることができます。この絶対インポートの振る舞いは将来のバージョン(おそらくPython 2.7)ではデフォルトになるでしょう。絶対インポートがデフォルトになると、import stringは常に標準ライブラリのバージョンを見つけます。ユーザーはできるだけ絶対インポートを使用し始めることをお勧めします。そのため、コードにfrom pkg import stringを記述することをお勧めします

2
jung rhew

John Bが言ったことに加えて、他のものを台無しにする可能性がある__package__を変更するのではなく、__main__変数を設定することが役に立つべきであるように思えます。しかし、私がテストすることができる限りでは、それは本来のように完全には機能しません。

私は同じ問題を抱えており、PEP 328も366も問題を完全に解決することはできません。どちらも、結局のところ、私が理解できる範囲でパッケージの先頭をsys.pathに含める必要があるからです。

私はそれらの変数に入るべき文字列をフォーマットする方法を私は見つけられなかったことにも言及すべきです。 "package_head.subfolder.module_name"ですか、それとも何ですか。

1
Gabriel

一番上のフォルダに "PYTHONPATH"環境変数を設定する方が簡単だとわかりました。

bash$ export PYTHONPATH=/PATH/TO/APP

その後:

import sub1.func1
#...more import

もちろん、PYTHONPATHは「グローバル」ですが、それでも私にとっては問題ありません。

1
Andrew_1510