2026年10月にリリース予定のPython 3.15のβ1がリリースされた。Python 3.15の新機能はこれで出そろったことから、どんなものが追加されたかをまとめてみました。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
どうもHPかわさきです。
Python 3.15β1のリリースを心待ちにしていた方はどのくらいいらっしゃるんでしょう。ボクはまあ心待ちにしていたんですが、こうやって実際にリリースされて、それを記事にまとめていると、「こんなことなら、もっと早くからいろいろなPEPを調べておけばよかった」と思ってしまいます(笑)。ホント、このギリギリにならないとやり始めないクセ、どうにかなりませんか?(どうにもなりません)
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 |
| 803、820、793 | 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パラメーターなしで読み込もうとすると例外が発生します。
UTF-8でエンコードされたテキストファイルを読み込むには画像の一番下にあるように「encoding='utf8'」のようなエンコーディングの指定が必要です。
これに対して、Python 3.15以降ではopen関数などのテキストIOで使われるデフォルトのエンコーディングがUTF-8になります。つまり、UTF-8エンコードのテキストファイルを読み込むのにencodingパラメーターの指定が必要なくなって、シフトJISなテキストファイルを読み込むにはencodingパラメーターの指定が必要になるということです(encoding='cp932'、encoding='sjis'、encoding='locale'など)。
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ではコードの見た目も変わることから、ここではこちらに含めることにしました。
もう一つ、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.15からは次のような書き方ができます。
# unpacking comprehensionあり
flatten = [*items for items in mylist]
print(flatten) # [1, 2, 3, 4]
これら2つの新しい書き方については次回にもう少し詳しく見ていくことにしましょう。
Python 3.15では以下の組み込み型が追加されます。
frozendictクラスは、その名前からも分かるように、内容を変更できない辞書です(とはいえ、辞書の値がリストのような変更可能なものであれば、リストの内容を変更することは可能です)。そのユースケースとしては次のようなことがPEP 814では挙げられています。
例として、frozendictを集合の要素にするコードの例を示します。
d0 = {'key': 'value'}
s0 = {d0} # TypeError
d1 = frozendict({'key': 'value'})
s1 = {d1}
print(s1) # {frozendict({'key': 'value'})}
このとき、「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
これらについても別の記事として取り上げる予定です。
また、mathモジュールに新たにintegerサブモジュールも追加されます(PEP 791)。これはmathモジュールにあった整数関連の関数をintegerサブモジュールに移そうというものです。mathモジュールからmath.integerサブモジュールに移行したものは以下。
ただし、これらの関数は従来通りに「math.comb」のようにしてアクセスできます(math.integerモジュールの個々の関数へのエイリアスとなっています)。よって、従来のコードからはそのままアクセスできますが、扱い的にはsoft deprecatedとなっているので、新規のコードではmath.integerモジュールを使うべきです(soft deprecatedなAPIは、廃止などは計画されておらず、警告も発生しないが、使うべきではないことを意味します)。
型システムの強化という観点では次のPEPがPython 3.15で採用されています。
このうち、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クラスの定義に注目してください。これは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では採用されませんでした。
正式版リリースの前にこうした記事をまとめるのはいかがなものかとも思いますが、個人的には、早めに調べ始めたと捉えることにします(笑)。
Copyright© Digital Advantage Corp. All Rights Reserved.