Python 3.15 β1がリリースされたので新機能や変更点をまとめてみたHPかわさきの研究ノート

2026年10月にリリース予定のPython 3.15のβ1がリリースされた。Python 3.15の新機能はこれで出そろったことから、どんなものが追加されたかをまとめてみました。

» 2026年05月15日 05時00分 公開
[かわさきしんじDeep Insider編集部]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

「HPかわさきの研究ノート」のインデックス

連載目次

Python 3.15β1のリリースを告げるPython Insiderのブログ記事 Python 3.15β1のリリースを告げるPython Insiderのブログ記事
Python Insiderより引用


かわさき

 どうもHPかわさきです。

 Python 3.15β1のリリースを心待ちにしていた方はどのくらいいらっしゃるんでしょう。ボクはまあ心待ちにしていたんですが、こうやって実際にリリースされて、それを記事にまとめていると、「こんなことなら、もっと早くからいろいろなPEPを調べておけばよかった」と思ってしまいます(笑)。ホント、このギリギリにならないとやり始めないクセ、どうにかなりませんか?(どうにもなりません)


Python 3.15β1の概要

 Python 3.15β1は2026年10月にリリースされる予定のPython 3.15のβリリース第1弾です。PEPベースで見たときに、「What's new in Python 3.15」に注目の機能として挙げられているのは以下です。ステータスは2026年5月13日時点のものです。

PEP タイトル ステータス
810 Explicit lazy imports for faster startup times Accepted
814 Add frozendict built-in type Final
661 Add sentinel built-in type Final
799 A dedicated profiling package for organizing Python profiling tools Accepted
799 Tachyon: High frequency statistical sampling profiler Accepted
831 Frame pointers are enabled by default for improved system-level observability Accepted
798 Unpacking in comprehensions Accepted
686 Python now uses UTF-8 as the default encoding Final
829 Package startup configuration files Accepted
728 TypedDict with typed extra items Accepted
747 Annotating type forms with TypeForm Final
800 Disjoint bases in the type system Accepted
782 A new PyBytesWriter C API to create a Python bytes object Final
803820793 Stable ABI for free-threaded builds and related C API 全てAccepted
788 Protection against finalization in the C API Final
791 math.integer Final
Python 3.15の新機能や変更点

 Python 3.15は、原則として新機能追加は終了し、以降は安定化フェイズに入ります。今後は何度かのβリリースを行った後、2026年8月と9月にリリース候補が、そして2026年10月に正式版がリリースされる予定です。

 上記のPEPを分類すると、次のようになります。

カテゴリ PEP
実行環境・パフォーマンス PEP 799、PEP 831、PEP 686、PEP 829、(JIT/末尾呼び出しインタプリターも)
新しい書き方 PEP 810、PEP 798
新しい組み込み型や標準モジュール PEP 814、PEP 661、PEP 791
型システム強化 PEP 728、PEP 747、PEP 800
C API関連 PEP 782、PEP 803、PEP 820、PEP 793、PEP 788
新機能や変更点を分類したもの

 「新しい書き方」に分類したPEP 810の「lazy import」は大規模なPythonアプリの起動を高速化させる技法なので、「実行環境・パフォーマンス」に含めるべきといえなくもないのですが、ここでは「新しい書き方」に入れておきます。

 以下では、それぞれのカテゴリについて簡単に紹介します。


かわさき

 C API関連のPEPについては省略します。だって、そこまで詳しくないですから(ゴメンなさい)。


実行環境・パフォーマンス

 このカテゴリには進化したプロファイラー(PEP 799)、デフォルトで有効化されたフレームポインタ(PEP 831)、.pthファイルに代わる新しいパッケージのスタートアップ構成ファイル(.site.tomlファイル)の登場(PEP 829)などがあります。PEPには含まれていませんが、JITの高性能化、Windows環境(64bit)での末尾呼び出しインタプリターの採用も大きな変更点といえるでしょう。Windows環境の末尾呼び出しインタプリターについては「Windows版Python 3.15はなぜ高速化するのか? その技術的根拠を読み解く」をご覧ください。

 それから、PythonのデフォルトのエンコーディングがUTF-8になりました(PEP 686)。「前からそうじゃない?」と思うかもしれません。実際、Python 3.0から、その内部ではUnicode文字列が使われていて、str.encodeメソッドなどで明示的にエンコーディングを指定しない場合はUTF-8が利用されます。その一方で、open関数などのテキストIOで使われるエンコーディングはOSのロケール設定に従ったものになっていたのです。

 例えば、日本語版Windows用のPythonでは、バージョン3.14まではテキストファイルを扱う際のデフォルトのエンコーディングは'cp932'が使われてきました。そのため、シフトJISでエンコーディングされているテキストファイルを読み込むときには、open関数などでencodingパラメーターを指定せずに読み込みが可能です。しかし、UTF-8でエンコーディングされているファイルをencodingパラメーターなしで読み込もうとすると例外が発生します。

Python 3.14でシフトJISエンコーディングのテキストファイル、およびUTF-8エンコーディングのテキストファイルを読み込んでみたところ Python 3.14でシフトJISエンコーディングのテキストファイル、およびUTF-8エンコーディングのテキストファイルを読み込んでみたところ

 UTF-8でエンコードされたテキストファイルを読み込むには画像の一番下にあるように「encoding='utf8'」のようなエンコーディングの指定が必要です。

 これに対して、Python 3.15以降ではopen関数などのテキストIOで使われるデフォルトのエンコーディングがUTF-8になります。つまり、UTF-8エンコードのテキストファイルを読み込むのにencodingパラメーターの指定が必要なくなって、シフトJISなテキストファイルを読み込むにはencodingパラメーターの指定が必要になるということです(encoding='cp932'、encoding='sjis'、encoding='locale'など)。

Python 3.15でシフトJISエンコーディングのテキストファイル、およびUTF-8エンコーディングのテキストファイルを読み込んでみたところ Python 3.15でシフトJISエンコーディングのテキストファイル、およびUTF-8エンコーディングのテキストファイルを読み込んでみたところ

 PEP 686自体は2022年に作られたもので、Python 3.10の頃から、かなりの時間をかけて、UTF-8をデフォルトのエンコーディングにしようと活動が続けられてきました。その一方で、今でもシフトJIS(CP932)なテキストファイルは広く使われています。それらをPythonで処理することもまたよくあることでしょう。

 デフォルトエンコーディングが変更になることに備えて、ファイルの読み書きでエンコーディングを意識したコードを書いてきたのであれば問題はないでしょう。そうでないのであれば、Python 3.15以降では既存のコードが動かなくなる可能性があります。エンコーディングの指定を確実に行っているかどうかを確認しておくことをオススメします。

新しい書き方

 大規模なPythonアプリは多くのモジュールに依存することがあります。それらをプログラムの起動時にimport文で全て読み込もうとすると、モジュールを読み込んで、トップレベルのコードを実行することになり(場合によってはバイトコードへのコンパイルも行われます)、非常に多くの時間がかかることになります。つまり、プログラムの起動に長い時間がかかるということです。

 これまでは、import文を関数の内部に閉じ込めたり、importlibを使ってオンデマンドにモジュールを読み込むような手法を使ったりして、プログラムの起動時に必要なモジュール全てが読み込まれることがないようにすることで、これを軽減していました。

 Python 3.15では、新たな解決策として、lazy import(PEP 810)という機能が追加されました。見た目的にはimport文またはfrom ... import文の先頭に「lazy」を付加するだけです。これにより、インポート対象のモジュールが実際に使われるまで、読み込みが遅延されるようになります。

lazy import <module_name>
lazy from <module_name> import <name>

lazy importの構文


かわさき

 プログラムの起動時間を短くするという意味では上で述べた「実行環境・パフォーマンス」というカテゴリに入れてもよかったのですが、lazy importではコードの見た目も変わることから、ここではこちらに含めることにしました。


 もう一つ、PEP 798で提案されている「unpacking comprehension」(内包表記でのアンパッキング)もPythonコードの書き方が変わる変更といえます。例えば、リストを要素とするリストをフラット化(平滑化)しようとすると、Python 3.14までは次のようなコードを書く必要がありました。

mylist = [[1, 2], [3, 4]]

# for文で書くと
flatten = []
for items in mylist:
    for item in items:
        flatten.append(item)

print(flatten)  # [1, 2, 3, 4]

# 内包表記を使うと
flatten = [item for items in mylist for item in items]

print(flatten)  # [1, 2, 3, 4]

Python 3.14までのコード

 しかし、Python 3.15からは次のような書き方ができます。

# unpacking comprehensionあり
flatten = [*items for items in mylist]
print(flatten)  # [1, 2, 3, 4]

内包表記でのアンパッキング

 これら2つの新しい書き方については次回にもう少し詳しく見ていくことにしましょう。

新しい組み込み型や標準モジュール

 Python 3.15では以下の組み込み型が追加されます。

  • frozendictクラス(PEP 814)
  • sentinelクラス(PEP 661)

 frozendictクラスは、その名前からも分かるように、内容を変更できない辞書です(とはいえ、辞書の値がリストのような変更可能なものであれば、リストの内容を変更することは可能です)。そのユースケースとしては次のようなことがPEP 814では挙げられています。

  • 変更不可能な辞書はハッシュ可能なので、辞書のキーに使ったり、集合(set)の要素にしたりできる
  • @functools.lru_cacheデコレーターで修飾された関数に渡す引数は、lru_cacheが内部で使用する辞書のキーとなる。変更不可能な辞書があれば、それをそうした関数に渡せるようになる
  • 関数のデフォルト引数値に変更不可能な辞書を指定することで、デフォルト引数値にまつわる問題を回避できるようになる

 例として、frozendictを集合の要素にするコードの例を示します。

d0 = {'key': 'value'}
s0 = {d0}  # TypeError

d1 = frozendict({'key': 'value'})
s1 = {d1}
print(s1)  # {frozendict({'key': 'value'})}

frozendictならハッシュ可能なので、集合の要素にできる

 このとき、「s2 = set(d1)」のように書くのはダメです。これは「s2 = set(d1.keys())」と書くのと同じことなので、{'key'}のような集合になります(dictに変更可能な辞書を渡しても同じようにキーを要素とする集合になります)。frozendictを集合の要素にするのであれば、集合リテラルとして書く必要があります。


かわさき

 そういえば、空集合を意味する表記を「{/}」としようというPEP 802はPython 3.15には入らなかったようですね。


 sentinelクラスはコンテナに特定の要素が含まれているかどうかを検索するような処理を書く際に、見つからなかったことを明確に記述できるようになります。以下に例を示します。

NOT_FOUND = sentinel('NOT FOUND')

def lookup(d, key):
    result = d.get(key, NOT_FOUND)
    if result is NOT_FOUND:
        print(f'not found: {key}')
    else:
        print(f'found: key {{{key}}}, value {{{result}}}')

d = {'mykey': None}
lookup(d, 'mykey'# found: key {mykey}, value {None}
lookup(d, 'other_key'# not found: other_key

sentinelクラスの使用例

 これらについても別の記事として取り上げる予定です。

 また、mathモジュールに新たにintegerサブモジュールも追加されます(PEP 791)。これはmathモジュールにあった整数関連の関数をintegerサブモジュールに移そうというものです。mathモジュールからmath.integerサブモジュールに移行したものは以下。

  • comb関数
  • factorial関数
  • gcd関数
  • isqrt関数
  • lcm関数
  • perm関数

 ただし、これらの関数は従来通りに「math.comb」のようにしてアクセスできます(math.integerモジュールの個々の関数へのエイリアスとなっています)。よって、従来のコードからはそのままアクセスできますが、扱い的にはsoft deprecatedとなっているので、新規のコードではmath.integerモジュールを使うべきです(soft deprecatedなAPIは、廃止などは計画されておらず、警告も発生しないが、使うべきではないことを意味します)。

型システム強化

 型システムの強化という観点では次のPEPがPython 3.15で採用されています。

  • PEP 728:TypedDict with Typed Extra Items
  • PEP 747:Annotating Type Forms
  • PEP 800:Disjoint bases in the type system

 このうち、PEP 800については「Python 3.15ではより正確な型チェックが可能に(なる予定) PEP 800で導入される非交和基底とは?」で取り上げています。

 PEP 728はTypedDictに関連するもので、TypedDictに対して、定義したキー以外のキーを持てない「閉じた」型として宣言したり、定義外のキーが存在する場合にその値の型を指定したりできるようにするものです。簡単な例を示します。

from typing import TypedDict

class Movie(TypedDict, closed=True):
    name: str
    year: int

class MovieWithDirector(TypedDict):
    name: str
    year: int
    director: str

def process(m: Movie) -> None:
    pass

mwd: MovieWithDirector = {'name': 'your name', 'year': 2016,
                          'director': 'makoto shinkai'}
process(mwd)  # closed=Trueなしだとエラーにならない、closed=Trueだとエラー

Movieクラスで許されるキーはnameとyearのみ。process関数はMovieクラスのインスタンスを受け取るので、MovieWithDirectorクラスのインスタンスを渡そうとするコードは正しくない

 ここでは閉じたクラスを例にしています。Movieクラスの定義に注目してください。これはTypedDictクラスのサブクラスで、'name'と'year'というキーを持つことになっています。そして、Python 3.15で追加される「closed=True」という指定もされています。これが閉じたクラスの定義です。つまり、Movieクラスのインスタンスで許されるキーは上記の2つだけであることを意味しています。

 MovieWithDirectorクラスもTypedDictクラスのサブクラスですが、こちらはもう1つ、'director'というキーも持てます。

 そして、process関数はMovieクラスのインスタンスを受け取って、何らかの処理をします。最後の行ではこの関数にMovieWithDirectorクラスのインスタンスを渡しています。しかし、Movieクラスは「closed=True」として定義されていて、2つのキー以外のキーは持てないことになっています。そのため、PEP 728をサポートしている型チェッカーはこのことをMovieクラスのインスタンスを渡すべきところで別のものを渡そうとしていることを検出して、エラーを報告します(「closed=True」がなければエラーにはなりません)。

 深い話をしだすと、構造的代入などについても触れなければならないので、ここでは詳細には触れませんが、このようなチェックを行えるように、Python 3.15ではPEP 728が採用されています。

 PEP 747は、型表現(type expression)をランタイムで評価した際に生成されるtype formオブジェクトに型注釈を付加する方法を定めたものです(詳細は省略します)。


かわさき

 筆者が少し前に「Pythonの仮想環境パスが.venvに統一される? PEP 832が提案される」で紹介した、PEP 832はPython 3.15では採用されませんでした。

 正式版リリースの前にこうした記事をまとめるのはいかがなものかとも思いますが、個人的には、早めに調べ始めたと捉えることにします(笑)。


「HPかわさきの研究ノート」のインデックス

HPかわさきの研究ノート

Copyright© Digital Advantage Corp. All Rights Reserved.

アイティメディアからのお知らせ

スポンサーからのお知らせPR

注目のテーマ

その「AIコーディング」は本当に必要か?
Microsoft & Windows最前線2026
4AI by @IT - AIを作り、動かし、守り、生かす
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。