# ディレクトリ構造 test/ __main__.py module01.py package01/ module02.py package02/ __init__.py module03.py package03/ __init__.py module04.py module05.py package04/ package05/ __init__.py module06.py
■確認用コード __main__.py
# -*- coding:utf-8 -*- # pylint: disable=C0413,C0114,C0305,C0116,C0103,C0411,C0209 # メインモジュールの状況 def output_info(): path = ", __path__ does not exist" if '__path__' in globals(): path = ", __path__ exist" print(f"{__package__=}, {__name__=}{path}") output_info() # ルートパスかつカレントパスのモジュール # OK import module01 # NG from . import module01 # ImportError import module01 module01.output_info() ## package01に__init__.pyなし # NG import package01 # package01.module02.output_info() # AttributeError # OK import package01.module02 # package01.module02.output_info() # OK from package01 import module02 # module02.output_info() # NG from . import package01 # ImportError # package01.module02.output_info() # NG from .package01 import module02 # ImportError # module02.output_info() from package01 import module02 module02.output_info() ## package02.__init__.pyの中身が空 # NG import package02 # package02.module03.output_info() # AttributeError # OK import package02.module03 # package02.module03.output_info() # OK from package02 import module03 # module03.output_info() # NG from . import package02 # ImportError # package02.module03.output_info() # NG from .package02 import module03 # ImportError # module03.output_info() from package02 import module03 module03.output_info() ## package03.__init__.py ## from . import module04 # OK import package03 <-- __init__.pyが空だとNGパターン # package03.module04.output_info() # OK import package03.module04 # package03.module04.output_info() # OK from package03 import module04 # module04.output_info() # NG from . import package03 # ImportError # package03.module04.output_info() # NG from .package03 import module04 # ImportError # module04.output_info() from package03 import module04 module04.output_info() ## package03.__init__.py ## from . import module04 # NG import package03 <-- module04だとOKパターン # package03.module05.output_info() # AttributeError # OK import package03.module05 # package03.module05.output_info() # OK from package03 import module05 # module05.output_info() # NG from . import package03 # ImportError # package03.module05.output_info() # NG from .package03 import module05 # ImportError # module05.output_info() from package03 import module05 module05.output_info() ## __init__.pyでimportされていないモジュールは ## __init__.pyの中身が空と同じ動き ## package04.package05.__init__.py ## from . import module06 # NG import package04 # package04.package05.module06.output_info() # AttributeError # OK import package04.package05 # package04.package05.module06.output_info() # OK import package04.package05.module06 # package04.package05.module06.output_info() # OK from package04 import package05 # package05.module06.output_info() # OK from package04.package05 import module06 # module06.output_info() # NG from . import package04 # ImportError # package04.package05.module06.output_info() # NG from .package04 import package05 # ImportError # package05.module06.output_info() # NG from .package04.package05 import module06 # ImportError # module06.output_info() from package04.package05 import module06 module06.output_info() import sys print("sys.path=[\n {}\n]".format("\n ".join(sys.path)))
■実行結果
__package__='', __name__='__main__', __path__ does not exist __package__='', __name__='module01', __path__ does not exist __package__='package01', __name__='package01.module02', __path__ does not exist __package__='package02', __name__='package02', __path__ exist __package__='package02', __name__='package02.module03', __path__ does not exist __package__='package03', __name__='package03', __path__ exist __package__='package03', __name__='package03.module04', __path__ does not exist __package__='package03', __name__='package03.module05', __path__ does not exist __package__='package04.package05', __name__='package04.package05', __path__ exist __package__='package04.package05', __name__='package04.package05.module06', __path__ does not exist
■備考
・__package__属性が空のモジュールでは相対importは使えない ・__path__属性を持つ「モジュール」は「パッケージ」 __init__.pyが存在するディレクトリは「モジュール」であり「パッケージ」 ※package01とpackage04は名前空間パッケージ(Namespace Package, Python 3.3から実装) ※package02とpackage03は通常パッケージ(Regular package) ※名前空間パッケージは別の場所にあっても構わない (名前空間パッケージとその配下は別プロジェクトに分割できる) PEP 420 – Implicit Namespace Packages ・モジュールの検索順 1) sys.builtin_module_names 2) sys.path 2-1) カレントパス 2-2) 環境変数PYTHONPATHのパス 2-3) pythonコマンドのインストール先