# ディレクトリ構造
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コマンドのインストール先