Python: 01. 型ヒント - ikymrkw/pydepot GitHub Wiki

型ヒントはオプション機能で、書かなくてもよいが、頑健でわかりやすいコードを書くためにはできるだけ使った方がよい。

型ヒントは静的・動的にチェック・強制されるわけではない。 プログラマーがコードそのものや doccomment を見て参考にするほか、 mypy などのツールや Visual Studio Code などの IDE が利用して型の不一致チェックや適切な補完を行う。

この解説が詳しい: 2021年度版Pythonの型ヒントの書き方 (for Python 3.9)

基本

最初に代入する際に、変数名の直後に : 型 という形式で記載する。

name: str = 'Alice'
age: int = 25

関数の仮引数にも変数と同様に付けられる。関数の戻り値は -> 型 という形式で記載する。戻り値がない場合は -> None とする。

def f() -> str:
    return "dummy"
def g(a: int, b: int = 123) -> int:
    return a + b
def do_something() -> None:
    # do ...

型はユーザ定義のクラスでも構わない。

Any と Type

任意の型を受け付けたい/受け付けざるを得ない場合は typing.Any を指定する。

from typing import Any

def f(a: Any) -> Any:
    ...

型そのものを受け付ける/返す場合は typing.Type というジェネリクス(後述)を使う。

from typing import Type

def get_handler_class(a: str) -> Type[MyClass]:
    ...

前方参照

まだ読み込みが完了していない型・クラスを型ヒントに指定するには、型名を文字列リテラルで指定する。

典型的な用途は、自分自身を返したり受け取ったりするクラスのメソッド。

class TreeNode:
    def get_parent(self) -> TreeNode:    # TreeNode クラスが未完成なのでエラーになる
        ...
    def get_parent2(self) -> "TreeNode": # これなら OK
        ...

コンテナ型(ジェネリクス)

list, tuple, dict のように、中に他の値を格納する(あるいはもっと一般的に、特定の型の値を扱う)クラスを指定するとき、単に list だけ指定してもあまり意味がない。

def f(names: list):
    s: str = ''
    for n in names:
        s += n  # この n の型は何???

そこで、コンテナ型の扱う型を記載する方法が用意されている。

def f(names: list[str]):
   n = names[0]  # n の型は str
list[str]       # 全要素が str の list, 長さは自由
list[str, str]  # 全要素が str で長さが 2 の list
tuple[str]      # str 要素1つだけの tuple
tuple[str, ...] # 任意長の tuple
dict[str, int]  # str -> int の dict

list でも tuple でもいいよ、という場合は、(後述するように Union[list, tuple]list | tuple と書くこともできるが、)両者の親の型を指定したほうがよい。詳細は省くが、中身を変えずに見るだけであれば、 Collection またはその親の Iterablelist, tuple, dict の共通の親インタフェースなので、これらを使うとよい(どう使うかに依存する)。Sequencelist のみの親なので注意。

# 以上は Python 3.9 以降の話 (PEP-0585)。Python 3.8 以前では typing モジュールを使う。

from typing import List, Tuple, Dict

def f(names: List[str]):
   n = names[0]  # n の型は str
List[str]       # 全要素が str の list, 長さは自由
List[str, str]  # 全要素が str で長さが 2 の list
Tuple[str]      # str 要素1つだけの tuple
Tuple[str, ...] # 任意長の tuple
Dict[str, int]  # str -> int の dict

あるいは from __future__ import annotations を書けば 3.9 以降の書き方が使えるようになる。