web-dev-qa-db-ja.com

pythonで相対インポートを実行する方法

stuff/
    __init__.py
    mylib.py
    Foo/
        __init__.py
        main.py
        foo/
            __init__.py
            script.py

script.pyインポートしたいmylib.py

これは単なる例ですが、実際には、親ディレクトリにあるモジュールの相対インポートを実行したいだけです。私はさまざまなことを試しましたが、このエラーが発生しました...

Attempted relative import beyond toplevel package

プログラムの開始点からのスクリプトがパッケージに含まれてはならないことをどこかで読んだので、そのように構造を変更してみました...

stuff/
    mylib.py
    foo.py // equivalent of main.py in above
    foo/
        __init__.py
        script.py

しかし、同じエラーが発生しました。

どうすればこれを達成できますか?これは適切なアプローチですか?

編集:In Python 2

23
random

もう少しいじってみたところ、設定方法がわかりました。具体的にするために、fooバー名は使用しません。私のプロジェクトディレクトリは次のように設定されています...

tools/
    core/
        object_editor/
            # files that need to use ntlib.py
            editor.py # see example at bottom
            __init__.py
        state_editor/
            # files that need to use ntlib.py
            __init__.py
        ntlib.py
        __init__.py # core is the top level package
    LICENSE
    state_editor.py # equivalent to main.py for the state editor
    object_editor.py # equivalent to main.py for the object editor

object_editor.pyの行は次のようになります...

from core.object_editor import editor

editor.pyの行は次のようになります...

from .. import ntlib

または代わりに

from core import ntlib

重要なのは、質問で挙げた例では、「メイン」スクリプトがパッケージ内から実行されていたということです。移動して特定のパッケージ(core)を作成し、エディターに共有してほしいライブラリ(ntlib)をそのパッケージに移動すると、すべてがおかしくなりました。

28
random

python PATHに「もの」が含まれていない限り、パスを追加する以外に選択肢はありませんでした。

たとえば、script.pyのレベルがわかっている場合は、次のようにできます。

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

私はWindows 7でPython 3.4.2を実行しています。これで髪の毛を引き裂きました。

これらのいずれかを実行する場合:

python -m unittest python -m unittest discover

...「トップレベルパッケージを超えて相対インポートを試みました」というエラーが表示されます。

私にとって、解決策は[..]を[test_stock.py]にドロップすることでした。ラインは:..stock import Stockから

変更:在庫インポートから

..そしてそれは動作します。

フォルダー構造:

C:\
  |
  +-- stock_alerter
             |
             +-- __init__.py
             +-- stock.py
             |
             \-- tests
                   |
                   +-- __init__.py
                   \-- test_stock.py
7
Allen May

[〜#〜] pep [〜#〜] から、相対インポートを使用して、パッケージ化されていないファイルをインポートすることはできないようです。

したがって、__init__.pyを追加して、インポートをfrom .mylib import *のようなものに変更する必要があります。

ただし、PEPはmylibをモジュールにパッケージ化しておくことを許可していないようです。したがって、ライブラリ関数の呼び出し方法を変更する必要がある場合があります。

もう1つの方法は、mylibをサブパッケージに移動し、from .libpackage import mylibとしてインポートすることです。

1
Dunes

import ..foo..stuff.mylib 大丈夫なはず

EDITは拡張機能を脱いだ

1
tekknolagi

Linuxまたはおそらく* nixを使用している場合は、これをシンボリックリンクでハックできます。

stuff/
    mylib.py
    foo.py // equivalent of main.py in above
    foo/
        script.py
        mylib.py  ->  ../mylib.py
    foo2/
        script2.py
        mylib.py  ->  ../mylib.py

これは、おそらく従うのに適したパターンではありません。

私の場合、別のディレクトリに配置する必要がある同じライブラリに依存する複数の実行可能ファイルがあったので、それを選択しました。

新しい実行可能テストの実装では、テスト作成者がpython importsを深く理解している必要はありません。

tests/
    common/
        commonlib.py
    test1/
        executable1.py
        executable2.py
        commonlib.py -> ../common/commonlib.py
    test2/
        executable1.py
        executable2.py
        commonlib.py -> ../common/commonlib.py