静的型付け言語からPythonにもどってくると、型を付けたほうが良いのかなと思うようになり、Pythonで型を注釈する方法をまとめます。
※Pythonでは3.5から型ヒントを使用できますが、このページではPython3.9以上の使用を想定しています。
参考ページ
typing --- 型ヒントのサポート — Python 3.11.3 ドキュメント
使用した環境
Windows10
Python 3.11.3
型ヒントの付け方
型ヒントはおもに変数、関数の引数、戻り値に対してつけることができます。
付け方は次のような形です。
変数: 型名
def 関数(引数: 型名) -> 戻り値の型
num: int = 8
num_f: float = 4.6
st: str = "Python"
li: list[str] = ["a", "b", "c"]
tu: tuple[str, int, str] = ("1", 2, "3")
di: dict[str, str] = {"Japan": "Tokyo", "China": "Beijing"}
se: set[int] = {3, 5, 7, 9}
def five_times(n: int) -> int:
return n * 5
型をチェックする方法
型をチェックするPythonの標準ライブラリや公式のツールはありません。
現状(2023)ではサードパーティ製の「mypy」が広く使われています。
pip install mypy
インストール後、mypyにファイルを渡します。
$ mypy typing1.py Success: no issues found in 1 source file
型ヒントをつけるメリット
ざっと思いつくメリットは3つあります。
- 可読性の向上
- ミスを減らす
- IDEやエディタでの補完が効く
1は説明するまでもないでしょう。
2に関して具体例を示すため、上の項目で出した関数をもう一度、掲載します。
def five_times(n: int) -> int:
return n * 5
print(five_times("5"))
指定している型と実際に渡した型は違っていますが、Pythonの文法上は問題ありませんから、実行してもエラーにはなりません。
$ py typing1.py 55555
短いコードですし、結果を出力しているため、ミスにはすぐ気づくかもしれませんが、これが長いコードや結果を見ないような場合はそうではないかもしれません。
$ mypy typing1.py typing1.py:4: error: Argument 1 to "five_times" has incompatible type "str"; expected "int" [arg-type] Found 1 error in 1 file (checked 1 source file)
型をチェックすることでミスの早期発見・削減につながります。
3が個人的には一番の理由ですが、使用するIDEやエディタによっては補完が効くようになります。
次の画像はVisual Studio Codeでの様子です。
型を付けない場合、この段階では「s」の型が分からないため補完が効いていません。
型を注釈することで文字列のメソッドの候補が表示されます。
ユースケース
異なる型の許容
複数の型の可能性がある場合、typingのUnionをインポートし、複数の型を注釈することができます。
from typing import Union
def five_times(n: Union[int, str]) -> Union[int, str]:
return n * 5
Python3.10以上なら、記号「|」を使って書くこともできます。
※インポートは不要
def five_times(n: int | str) -> int | str:
return n * 5
何にでも適合するAny型、というのもあります。
※インポートが必要
from typing import Any
def five_times(n: Any) -> Any:
return n * 5
ただし、この場合は注釈しないことと同義です。
リストで異なる型を許容するには、上記と同じようにUnionを使用します。
固定長で変更しなくても良いならタプルも使えます。
クラス
クラスの初期化メソッド「__init__」を介してメンバ変数に型の注釈を行います。
class Gorilla:
def __init__(self, age: int, home: str) -> None:
self.age = age
self.home = home
shabani = Gorilla(27, "Higashiyama")
dataclassesのdataclassをデコレータとして使うと、次のように書くこともできます。
from dataclasses import dataclass
@dataclass
class Gorilla:
age: int
home: str
shabani = Gorilla(27, "Higashiyama")
個人的にはこちらの方が見やすいですね。