🎃

Python 3.12 の新機能試してみた

2023/10/06に公開

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 以下の型宣言が、変数と混同してしまってわかりづらいと思っていたので、この変更は嬉しいです。

他にも様々な機能が追加されています。詳細は以下を参照してください。

https://peps.python.org/pep-0695/

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' }' }')

参考:

https://peps.python.org/pep-0701/

インタプリターごとの GIL

Python3.12 では、同一プロセス内のインタプリターが GIL を共有しないようにできるようになった模様。

現状は C-API でのみ利用可能であり、 一般的な Python ユーザーにはほぼ関係なさそう。Python 3.13 以降での GIL をオプションにする PEP 703 のための機能だと思われます。

参考:

https://peps.python.org/pep-0684/

型ヒント関連

**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)

参考:

https://peps.python.org/pep-0692/

@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

参考

https://docs.python.org/3.12/whatsnew/3.12.html

Discussion