Python 3 での相対インポート 質問する

Python 3 での相対インポート 質問する

同じディレクトリ内の別のファイルから関数をインポートしたい。

通常、次のいずれかが機能します。

from .mymodule import myfunction
from mymodule import myfunction

...しかし、もう 1 つでは、次のエラーのいずれかが発生します。

ImportError: attempted relative import with no known parent package
ModuleNotFoundError: No module named 'mymodule'
SystemError: Parent module '' not loaded, cannot perform relative import

どうしてこれなの?

ベストアンサー1

残念ながら、このモジュールはパッケージ内に存在する必要があり、場合によってはスクリプトとして実行可能である必要もあります。これを実現する方法はありますか?

このようなレイアウトになるのはよくあることです...

main.py
mypackage/
    __init__.py
    mymodule.py
    myothermodule.py

...mymodule.pyこんな感じで...

#!/usr/bin/env python3

# Exported function
def as_int(a):
    return int(a)

# Test function for module  
def _test():
    assert as_int('1') == 1

if __name__ == '__main__':
    _test()

...myothermodule.pyこんな感じ...

#!/usr/bin/env python3

from .mymodule import as_int

# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

...そしてmain.pyこんな感じ...

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__main__':
    main()

... または を実行すると正常に動作しますmain.pymypackage/mymodule.py、 ではmypackage/myothermodule.py相対インポートのため失敗します...

from .mymodule import as_int

これを実行するには、-m オプションを使用して、Python モジュール システム (ファイルシステムではなく) のパスを指定します...

python3 -m mypackage.myothermodule

...しかし、これはやや冗長であり、 のようなシェバン行とうまく混在しません#!/usr/bin/env python3

別の方法としては、相対インポートの使用を避けて、単に... を使用することです。

from mypackage.mymodule import as_int

いずれにしても、 の親から実行するmypackageか、そのディレクトリを に追加する必要があります(どちらにしても、が sys.path にあるPYTHONPATHことが保証されます)。mypackageモジュール検索パス)。または、すぐに動作させたい場合は、PYTHONPATHまず次のようにコード内のコードを修正します...

import sys
import os

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(SCRIPT_DIR))

from mypackage.mymodule import as_int

ちょっと面倒ですが、その理由の手がかりはEメールグイド・ヴァン・ロッサムという人物によって書かれたものです...

私はこれと、この仕組みをいじくり回す他の提案に対しては -1 です__main__。唯一の使用例は、モジュールのディレクトリ内にあるスクリプトを実行することのようですが、私はこれを常にアンチパターンだと思っています。私の考えを変えるには、そうではないと私を説得する必要があります。

パッケージ内でスクリプトを実行することがアンチパターンであるかどうかは主観的ですが、個人的には、カスタム wxPython ウィジェットがいくつか含まれているパッケージでは、wx.Frameテスト目的で任意のソース ファイルのスクリプトを実行してそのウィジェットのみを表示できるので、非常に便利だと思います。

おすすめ記事