Python Monthly Topics

Python 3.15新機能⁠lazy imports(遅延インポート)紹介

鈴木たかのり@takanoryです。今月の「Python Monthly Topics」では、2026年10月に正式版がリリース予定[1]のPython 3.15の新機能から、lazy imports(遅延インポート) を紹介します。

Python 3.15の新機能を試すには、現在リリースされているβ版をインストールしてください。本記事執筆時点ではPython 3.15.0 beta 3がダウンロード可能です。

lazy imports(遅延インポート)とは

lazy importsはPEP 810で提案された機能で、Python 3.15で新機能として追加されます。まずはPEP 810の概要文からlazy importsがどういう機能かを確認します。

import文に新しいソフトキーワードlazyを付加することにより、遅延インポートとなります。

lazy import json
lazy from json import dumps

遅延インポートされたモジュールは、そのモジュールが使用されるまでは読み込まれません。通常のインポート文はimport jsonと書かれた行をPythonが実行した段階で、モジュールが読み込まれて実行されます。

遅延インポートを使用することにより、Pythonプログラムの起動時間、メモリ使用量や不要な処理を削減することを目的としています。この機能が有効な例としてはコマンドラインツール、テスト、依存関係が複雑なアプリケーションが上げられています。

通常のインポート文は変更せず、lazyソフトキーワードの付いた遅延インポートのみで有効となるため、下位互換性が維持されています。

lazy importsのパフォーマンスを確認する

簡単なサンプルコードでlazy importsのパフォーマンスを確認します。以下の簡単なPythonスクリプトを用意します。このコマンドはjsonモジュールとdatetimeモジュールをインポートしています。

cli.py - サンプルのPythonスクリプト
import argparse
import datetime
import json


def main():
    parser = argparse.ArgumentParser(description="lazy imports sample program")
    parser.add_argument('filename')
    parser.add_argument('-c', '--count')
    parser.add_argument('-v', '--verbose', action='store_true')
    args = parser.parse_args()

    with open(args.filename) as f:
        data = json.load(f)
    print(data)
    print(datetime.datetime.now())


if __name__ == "__main__":
    main()

もう1つのPythonスクリプトは同様のコードですが、2つのモジュールのインポート文がlazy importになっています。

cli_lazy.py - lazy importを使用したサンプルのPythonスクリプト
import argparse
lazy import datetime  # lazy import
lazy import json  # lazy import


def main():
    parser = argparse.ArgumentParser(description="lazy imports sample program")
    parser.add_argument('filename')
    parser.add_argument('-c', '--count')
    parser.add_argument('-v', '--verbose', action='store_true')
    args = parser.parse_args()

    with open(args.filename) as f:
        data = json.load(f)
    print(data)
    print(datetime.datetime.now())


if __name__ == "__main__":
    main()

この2つのスクリプトを--helpオプションを指定して呼び出してみます。1回だと処理時間に大きな差がないので100回実行します。--helpオプションを指定するとこのスクリプトはargparseがヘルプメッセージを出力して、そこで終了します。そのため、cli_lazy.pyの場合はjson、datetimeモジュールが実際にはインポートされません。

結果は以下の通りで、cli_lazy.pyがわずかに速いことがわかります。このように、lazy importsを活用することにより、不要なモジュールがインポートされないことでプログラムのパフォーマンスを上げることができます。

各スクリプトを100回実行
% time seq 100 | xargs -I {} python3.15 cli.py --help > /dev/null
2.06s user 0.45s system 90% cpu 2.780 total
% time seq 100 | xargs -I {} python3.15 cli_lazy.py --help > /dev/null
2.00s user 0.43s system 90% cpu 2.667 total

lazy importsの仕組み

このlazy importsはどのように動作しているのでしょうか? lazyソフトキーワードのついたインポート文を実行すると、モジュールは読み込まれずに遅延プロキシオブジェクトが作成され、そのオブジェクトがモジュール名と関連付けられます。そして、モジュールが使用されるタイミングでプロキシオブジェクト経由でモジュールが読み込まれます。

以下は対話モードでlazy importを実行した例です。

>>> import sys
>>> lazy import json  # lazy importを実行
>>> 'json' in sys.modules  # モジュール一覧にjsonが存在しない
False
>>> result = json.dumps({"hello": "world"})  # jsonモジュールの関数を実行
>>> 'json' in sys.modules  # モジュール一覧にjsonが存在する
True

lazy importsの言語仕様

lazyソフトキーワードはどこでも使用できるわけではありません。グローバルレベルでしか使用できないため、以下のような書き方は構文エラーとなります。また、import *from __future__ import文でもlazyソフトキーワードは使用できません。

lazyソフトキーワードを使用できないパターン
# SyntaxError: lazy import not allowed inside functions
# シンタックスエラー:関数の中でlazy importはできない
def foo():
    lazy import json

# SyntaxError: lazy import not allowed inside classes
# シンタックスエラー:クラスの中でlazy importはできない
class Bar:
    lazy import json

# SyntaxError: lazy import not allowed inside try/except blocks
# シンタックスエラー:try/exceptの中でlazy importはできない
try:
    lazy import json
except ImportError:
    pass

# SyntaxError: lazy from ... import * is not allowed
# シンタックスエラー:lazy from ... import * とは書けない
lazy from json import *

# SyntaxError: lazy from __future__ import is not allowed
# シンタックスエラー:lazy from __future__ importとは書けない
lazy from __future__ import annotations

__lazy_modules__を使用してPython 3.14でも動作させる

lazy importはPython 3.15以降の機能のため、それ以前のPythonで実行しようとすると当然ですが構文エラーが発生します。

Python 3.14でcli_lazy.pyを実行
% python3.14 cli_lazy.py
 File ".../cli_lazy.py", line 2
   lazy import datetime  # lazy import
        ^^^^^^
SyntaxError: invalid syntax

Python 3.15以降ではlazy importにして3.14以前でも動作させるためにはどうすればよいでしょうか? そのためには__lazy_modules__という変数を定義し、その中にlazy importの対象となるモジュールの名前を列挙します。以下のように書くと(後半は省略しています⁠⁠、Python 3.14では今まで通り普通にインポートされ、Python 3.15ではdatetimeとjsonモジュールがlazy importの対象となります。

cli_lazy_modules.py - __lazy_modules__を使用した例
__lazy_modules__ = ["datetime", "json"]

import argparse
import datetime
import json


def main():
    parser = argparse.ArgumentParser(description="lazy imports sample program")
    parser.add_argument('filename')

各バージョンのPythonで動作することが確認できます。

Python 3.14、3.15どちらでも動作する
% python3.14 cli_lazy_modules.py --help
usage: cli_lazy_modules.py [-h] [-c COUNT] [-v] filename

...
% python3.15 cli_lazy_modules.py --help
usage: cli_lazy_modules.py [-h] [-c COUNT] [-v] filename

...

コードを書き換えずにlazy importを有効にする

既存のコードを書き換えずにPythonプログラム実行時にlazy importを有効にする方法があります。それは-X lazy_importsオプションと、PYTHON_LAZY_IMPORTS環境変数です。このオプションと環境変数はどちらもallまたはnormalという値を指定できます。normalはデフォルト値で、lazyソフトキーワードが存在するとlazy importします。allを指定すると、すべてのインポート文のデフォルト動作がlazy importとなります。

また、実行中のプログラムに対してsys.set_lazy_imports()関数とsys.get_lazy_imports()関数によって、この値を設定、取得できます。

実体をインポートするときにエラーが発生する

次のコード例は関数名をtypo(綴り間違え)しています。

typo.py - 関数名をtypoしている例
lazy from json import dumsp  # dumpsをtypoしている

print("アプリケーションは正常に開始")
print("データを処理する...")

# 関数を最初に使用するときにエラーが発生する
result = dumsp({"key": "value"})

このようなプログラムを実行した場合、今まではimport文でエラーが発生していましたが、lazy importでは実体をインポートするときにエラーが発生します。2つのprint()関数は正常に動作し、そのあとの7行目のtypoしたdumsp()関数を実行するときにインポートエラーが発生しています。エラーメッセージではlazy importで遅延インポートするときに例外が発生し、その結果として関数の実行でエラーとなった、という内容になっています。

% python3.15 typo.py
アプリケーションは正常に開始
データを処理する...
Traceback (most recent call last):
  File ".../typo.py", line 1, in <module>
    lazy from json import dumsp  # sumpsをtypoしている
ImportError: lazy import of 'json.dumsp' raised an exception during resolution

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File ".../typo.py", line 7, in <module>
    result = dumsp({"key": "value"})
             ^^^^^
ImportError: cannot import name 'dumsp' from 'json' (.../python3.15/json/__init__.py).
  Did you mean: 'dump'?

まとめ

Python 3.15の新機能lazy imports(遅延インポート)について紹介しました。シンプルな機能ですが最初に説明したとおり、コマンドラインツール、テスト、依存関係が複雑なアプリケーションの起動速度やメモリ使用量の削減にメリットがあると思います。

ぜひ試してみてください。

参考資料

おすすめ記事

記事・ニュース一覧