[Python >= 3.3] import と from と __init__.py

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