2022年2月28日月曜日

Python の TypeGuard 超入門

Python の TypeGuard 超入門

概要

前回 は型ヒントを使って事前に型チェックする方法を紹介しました

今回は TypeGuard を紹介します
簡単に言えば型をチェックする関数を独自で定義することができる機能です

環境

  • macOS 11.6.4
  • Python 3.10.2

サンプルコード

from dataclasses import dataclass
from typing import TypeGuard


@dataclass
class User():
    name: str
    age: int


def is_user(user: User) -> TypeGuard[User]:
    if isinstance(user, User):
        return True
    return False


def print_user(user: User):
    if is_user(user):
        print(user.name)
        print(user.age)
    else:
        print("The argument type must be the User class.")


if __name__ == '__main__':
    user = User("hawk", 10)
    print_user(user)
    print_user("hawk")

解説

TypeGuard を使っているのは is_user 関数です
戻り値のアノテーションを TypeGuard[User] にし戻り値を boolean にすることで指定の引数が User クラスかどうかを判定する独自の TypeGuard 関数であることを明示しています

あとは型チェックしたい箇所 (print_user) で is_user を呼び出します

実際にこのコードを実行するとエラーなく終了してしまいますがこのあと紹介する型チェックツールを使うことで事前に型エラーを検知することができるようになります

型チェック

過去の記事では mypy というチェックツールを紹介しました
今回は pyright を使ってみました
mypy でも同じように型チェックは可能です

pyright というツールがあるのでこれを使って型チェックしてみます

  • pip install pyright
  • pyright app.py
No configuration file found.
No pyproject.toml file found.
stubPath /Users/hawk/Documents/work/try_python/typings is not a valid directory.
Assuming Python platform Darwin
Searching for source files
Found 1 source file
/Users/hawk/Documents/work/try_python/app.py
  /Users/hawk/Documents/work/try_python/app.py:28:16 - error: Argument of type "Literal['hawk']" cannot be assigned to parameter "user" of type "User" in function "print_user"
    "Literal['hawk']" is incompatible with "User" (reportGeneralTypeIssues)
1 error, 0 warnings, 0 informations 
Completed in 0.779sec

hawk という文字列は User クラスではないというエラーが表示されています
こんな感じで事前チェックでは型が違うよという警告がちゃんと表示されます

最後に

Typing を使うと事前に型チェックすることが可能になるので関数に意図しないオブジェクトを渡すことを防ぐことができます
便利な機能ではありますがアノテーションや NewType ヘルパーを使う必要が出てくるのでコードは増えがちです

そもそも型あり言語を使ったほうがいいような気もしますが動的型付けとハイブリットで使いたい場合にはいいのかもしれません

また実際に実行しただけだとエラーにはならないので Typing を使う場合には IDE や mypy のように CI などで事前チェックするような機構が必要になるかなと思います

参考サイト

0 件のコメント:

コメントを投稿