前書き
Python の相対インポートと絶対インポート、これら 2 つの概念は、パッケージ内のインポートに対する相対的なものです。パッケージ内インポートとは、パッケージ内のモジュールがパッケージ内のモジュールをインポートすることを意味します。
Python importのパスを検索
カレントディレクトリ内のモジュールを検索
環境変数PYTHONPATHに指定されたパスリストを順に検索
Pythonのインストールパスのlibライブラリを検索
Pythonの手順import
ロードされたPythonのすべてのモジュール情報はsys.modules構造体に格納されます。 モジュールをインポートする場合、次の手順が実行されます。
Aをインポートする場合は、sys.modulesにすでにAがあるかどうかを確認します。存在する場合はロードされません。存在しない場合は、A のモジュール オブジェクトを作成して A をロードします
それが A から B をインポートした場合は、まず A のモジュール オブジェクトを作成し、次に A を解析し、そこから B を見つけて、それを A の __dict__ に入力します
相対インポートと絶対インポート
絶対インポート形式は import A.B または from A import B で、相対インポート形式は from インポート B または from ..A import B. を表します。現在のモジュール、.. は上位レベルのモジュールを表し、... は上位レベルのモジュールを表します。
相対インポートにより、ハードコーディングによって引き起こされるメンテナンスの問題を回避できます。たとえば、トップレベルのパッケージの名前を変更すると、そのサブパッケージのすべてのインポートが使用できなくなります。ただし、相対インポート ステートメントを含むモジュールは直接実行できません。そうでない場合は、例外が発生します。
ValueError: Attempted relative import in non-package
これの理由は何ですか?モジュールをインポートするときは、最初にいくつかのルールを理解する必要があります:
パッケージ構造が明示的に指定されていない場合、Python は __name__ に基づいてパッケージ内のモジュールの構造を決定します。パッケージ構造ではありません。A.B.C 構造の場合、最上位モジュールは A です。基本的に次の原則に従います:
それが絶対インポートの場合、モジュールはそれ自身のサブモジュール、またはその最上位モジュールと同じレベルのモジュールとサブモジュールのみをインポートできます
それが相対インポートの場合、モジュールはパッケージ構造 そして、最上位モジュール内のモジュールのみをインポートできます
モジュールが直接実行される場合、それ自体が最上位モジュールであり、階層がないため、他の相対パスは見つかりません。
Python2.x のデフォルトは相対パス インポート、Python3.x のデフォルトは絶対パス インポートです。絶対インポートでは、サブパッケージのインポートによる標準ライブラリ モジュールの上書き (同じ名前による競合) を回避できます。 Python2 でデフォルトで絶対インポートを使用する場合 (暗黙的な相対インポート)、明示的な相対インポート (表示相対インポート) は無効になりません。
それでは、暗黙的な相対インポートとは何であり、明示的な相対インポートとは何でしょうか?次のパッケージ構造を仮定して、例を見てみましょう:
from __future__ import absolute_import
thing ├── books │ ├── adventure.py │ ├── history.py │ ├── horror.py │ ├── __init__.py │ └── lovestory.py ├── furniture │ ├── armchair.py │ ├── bench.py │ ├── __init__.py │ ├── screen.py │ └── stool.py └── __init__.py
最後に、相対インポートと絶対インポートはパッケージ内インポートにのみ適用されることを再度強調します。そうしないと、この記事で説明する内容は無意味になります。いわゆるパッケージは、__init__.py ファイルが含まれるディレクトリです。このファイルは、パッケージが空の場合もあれば、任意の正規の Python コードを追加する場合にも実行されます。
相対インポートはハードコーディングを回避でき、パッケージのメンテナンスに適しています。絶対インポートにより、標準ライブラリとの名前の競合を回避できます。実際、カスタム モジュールに標準ライブラリと同じコマンドを含めることは推奨されません。
import bench # 此为 implicit relative import from . import bench # 此为 explicit relative import from furniture import bench # 此为 absolute import