Python3.10で追加された型ヒント関連機能から、 PEP 613 Explicit Type Aliases を解説します。
型エイリアス¶
型エイリアスは、型定義に別名をつける機能です。
型エイリアスの定義は、見た目はただの代入文と区別が付きません。モジュールのトップレベルで型を代入すると、左辺の名前は右辺の型別名となります。
例として、
Username = str
と書けば、str
型の別名として、Username
という型名を使えるようになります。
str
型を使って
username: str = "test user"
と書いても、Username
型を使って
username: Username = "test user"
と書いても、まったく同じ型ヒントになります。
このように、代入文で型に別名をつけるのはPythonとしてごく普通の動作で、最初に型ヒントが登場したときには、静的な型チェッカでも同じ使い方をするのはわかりやすいと想定されていたのでしょう。
しかし、これだけでは単なる代入文と型エイリアスの区別がつかず、書き間違いがあってもわかりやすいエラーメッセージを表示するのが難しい場合があります。例えば、
def F()->None:pass
MyType1 = F
a: MyType1
というプログラムは、mypy
で型チェックを行うと次のエラーとなります。
test.py:5: error: Variable "test.MyType1" is not valid as a type
このエラーは、MyType1
が有効な型の名前となっていないために発生します。
このプログラムを書いた人は、型エイリアスを定義するつもりで、
MyType1 = F
と書いたのでしょう。しかし、F
は型ではなく関数オブジェクトなので、 MyType1
は型エイリアスの定義とはなりません。
それなのに
a: MyType1
と、変数 a
を MyType1
型と宣言しているので、この行でエラーが発生しています。
このエラーを解消するには、MyType1 = F
の行を修正して、右辺に正しい型を指定する必要があります。本来、この行でエラーを発生して、開発者に間違ってますよ、と伝えるべきです。しかし、現在の仕様では、MyType1 = F
が正しくない型エイリアスの定義とは認識できず、たんなる代入文でしかないため、この行ではエラーを出すのが困難です。
そこで、PEP 613 では typingモジュールに新しく TypeAlias
を追加し、型エイリアスの 型 として明示的に定義できるようになりました。
from typing import TypeAlias
def F()->None:pass
MyType1:TypeAlias = F
a: MyType1
このように記述すれば、mypyなどの型チェッカは TypeAlias
に F
を指定していることを検出し、わかりやすくこの行でエラーを出力できるようになります。
前方参照¶
Pythonの型ヒントでは、まだ定義されていない型を参照するときには、文字列で型名を指定できます。
a: "SampleType"
class SampleType:
pass
しかし、型エイリアスには、文字列を使った前方参照を指定できません。次のように型エイリアスを文字列で指定しても、エラーとなります。
MyType2 = "SampleType"
a: MyType2
class SampleType:
pass
MyType2
に代入されているのは型ではなく文字列なため、型エイリアスの定義とは認められません。
この場合も、次のように TypeAlias
を使って明示的に型エイリアスを定義すると
MyType2: TypeAlias = "SampleType"
型チェッカはMyType2
が型エイリアスであることを理解して、型名として利用できるようになります。