Python3.12でtype文による型エイリアスが出来るようになっていた

PythonLiteral型について調べる過程で学んだことを記録。

そのため今回はtype文を中心に書きます。

今回の検証環境は以下の通りです。

type文とは

type文はPython3.12から追加された型エイリアスを定義するための構文です。

7.14. The type statement

英語だと、type statementと表現するようです。

PEP695で提案されたようでした。

これまでの型エイリアスの定義方法

これまで、型エイリアスを定義する方法は2つありました。

  1. 代入によって作成する方法
  2. TypeAliasでマークする方法

代入によって作成する方法

区切り文字を表す、Delimiterという型エイリアスを定義する例を書きます。 Literalを利用してDelimiter,:を許可するようにしています。

from typing import Literal
Delimiter = Literal[",", ":"]

TypeAliasでマークする方法

from typing import Literal, TypeAlias
Delimiter: TypeAlias = Literal[",", ":"]

type文を利用した定義方法

type文では先頭にtypeと記載するのみです。

from typing import Literal
type Delimiter = Literal[",", ":"]

これまでのコードを見てみると、ちょっとした違いはあれど大きな違いはないと感じました。

実際に動かしてみる

例えば以下の引数delimiter: Delimiterを第2引数に期待する関数を定義して、意図する値・意図しない値で呼び出してみます。

関数定義

def split_text(text: str, delimiter: Delimiter) -> None:
    pass

上記のsplit_textを呼び出した場合の値

# OK例1
split_text("a,b,c", ",")

# OK例2
split_text("a:b:c", ":")

# NG例
# mypy側で以下のエラーが出る
# error: Argument 2 to "split_text" has incompatible type "Literal['|']"; expected "Literal[',', ':']"  [arg-type]
split_text("a|b|c", "|")

実際に使用する場合の注意点

執筆時の最新のmypyバージョン 1.10.1 ではまだtype文は未対応のようでした。

そのためtype文を利用すると、error: PEP 695 type aliases are not yet supported [valid-type]と表示されます。

エラーを許容はしにくいと思うので、現状では代入かTypeAliasで定義することになりますが、TypeAliasはPython3.12でtype文導入に伴い、非推奨となったようでした。

typing.TypeAlias に記載があります。

以上からmypyの現状も鑑みると代入を利用するのが良さそうに思っています。

自分が動かしてみた時にエラーが出てStack overflowにも同様の質問がされており、知りました。毎度思いますが、最初にこうやってオープンな場で質問してくれる人、本当にありがたい・・・

Mypy error: PEP 695 type aliases are not yet supported

Pythonの型ヒント周りは割とバージョンによって変わることが多いので、これからも新バージョンが出た際には精力的にキャッチアップが必要だなと感じました。