2026年6月: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モジュールをインポートしています。
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()
もう一つのPythonスクリプトは同様のコードですが、2つのモジュールのインポート文がlazy importになっています。
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を活用することにより、不要なモジュールがインポートされないことでプログラムのパフォーマンスを上げることができます。
% 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が存在しない
>>> 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で実行しようとすると当然ですが構文エラーが発生します。
% 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の対象となります。
__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で動作することが確認できます。
% 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(綴り間違え)しています。
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(遅延インポート)について紹介しました。 シンプルな機能ですが最初に説明したとおり、コマンドラインツール、テスト、依存関係が複雑なアプリケーションの起動速度やメモリ使用量の削減にメリットがあると思います。
ぜひ試してみてください。