Python 3.12 の新機能試してみた
2023/10/2 に Python 3.12 がリリースされました。
今回は、Python 3.12 の気になった新機能を試してみました。
型パラメータ構文
Generics 関連
Python にも他の言語のジェネリクスのような記法が追加されました。
Generics 関数
Python3.11 以下の場合:
from typing import TypeVar
T = TypeVar('T')
def max(a: T, b: T) -> T:
return a if a > b else b
Python3.12:
def max[T](a: T, b: T) -> T:
return a if a > b else b
Generics クラス
Python3.11 以下:
from typing import TypeVar
T = TypeVar('T')
class Item:
def __init__(self, value: T) -> None:
self.value = value
Python3.12:
class Item[T]:
def __init__(self, value: T) -> None:
self.value = value
型エイリアス宣言キーワード追加
型エイリアスを宣言するための type
キーワードが追加されました。
Python3.11 以下:
IntOrStr = int | str
def func(value: IntOrStr) -> None:
print(value)
Python3.12:
type IntOrStr = int | str
def func(value: IntOrStr) -> None:
print(value)
ジェネリクスと組み合わせることもできます。
type ListOrValue[T] = list[T] | T
再帰的な型宣言時に文字列で型宣言する必要がなくなりました。
Python3.11 以下:
from typing import Union
Tree = list[Union[int, 'Tree']]
Python3.12:
type Tree = list[int | Tree]
Python3.11 以下の型宣言が、変数と混同してしまってわかりづらいと思っていたので、この変更は嬉しいです。
他にも様々な機能が追加されています。詳細は以下を参照してください。
f-string の制限緩和
Python3.11 以下では f-string 内の式で、f-string の外側のクォートを使うことができませんしたが、Python3.12 では使えるようになりました。
Python3.11 以下は SyntaxError.
name = {'John': 'Doe' }
print(f'Hello { name['John'] }')
ネストされた f-string も使えます。
print(f'Hello {f'John { f'Doe' }' }')
参考:
インタプリターごとの GIL
Python3.12 では、同一プロセス内のインタプリターが GIL を共有しないようにできるようになった模様。
現状は C-API でのみ利用可能であり、 一般的な Python ユーザーにはほぼ関係なさそう。Python 3.13 以降での GIL をオプションにする PEP 703 のための機能だと思われます。
参考:
型ヒント関連
**kwargs
の正確な型付け
Python 3.11 以下では、 **kwargs
の値が同じであれば型を付与できました。
# **kwargs : dict[str, int]
def func(**kwargs: int) -> None:
print(kwargs)
func(a=1, b=2)
Python 3.12 では、 **kwargs
の値が異なる場合でもパラメータごとに、 TypedDict
で型を付与できるようになりました。
from typing import TypedDict, Unpack
class Args(TypedDict):
a: str
b: int
def func(**kwargs: Unpack[Args]) -> None:
print(kwargs)
func(a='a', b=1)
参考:
@override
デコレーター
Python 3.12 では、 @override
デコレーターが追加されました。
@override
デコレーターは、メソッドが親クラスのメソッドをオーバーライドしていることを明示的に示すために使用します。
from typing import override
class Parent:
def func(self) -> None:
pass
class Child(Parent):
@override
def func(self) -> None:
pass
参考
Discussion