My External Storage

Dec 30, 2019 - 4 minute read - Comments - python

[Python3.8] TypedDictとPyCharmを使うと型ヒントの圧倒的な恩恵を享受できる

業務でも趣味でもPythonを書くときはPython3.8を使っている。
Python3.8から使えるTypedDictとPyCharmを組合わせた開発体験が素晴らしいので紹介する。

TL;DR

  • TypedDeictはPEP589で提案され、Python3.8から使える型ヒント
  • 辞書型のキーとセットをクラスとして厳密に定義できる
  • PyCharmと組み合わせると以下の恩恵が受けられる
    • オブジェクト生成時に不足キーがわかる
    • Keyを設定するときに型が異なることがわかる
    • Valueアクセスの際にキーが存在するかわかる
    • Valueの型情報に対して補完が可能
class UserDict(TypedDict):
    user_name: str
    email: str

なお、この記事は以下の環境を使っている。

  • Python 3.8.0
  • Pycharm 2019.3.1 PROFESSIONAL

事前準備

Python3.8の実行環境は次のように用意する。
まず、pipenvpyenvを事前に準備し、テスト用のディレクトリを作ってpipenvでPython3.8環境を作っておく。

# 私はMacなのでbrewでインストール
$ brew install pipenv pyenv
$ pipenv --python 3.8

Pipfileが生成できたら、PyCharmで対象ディレクトリを開く。
PycharmのPython実行環境は、Preferenceの中から「Project: xxx」→ 「Project Interpreter」を開いてPython3.8を認識している状態にしておく。

TypedDictを使ったクラス定義とPyacharm

最近のPythonは型ヒントを使って型付けをしているかのようにコーディングができる。

TypedDictはPEP589でPython3.8から追加された型ヒントだ。TypedDictを使うことで辞書型の型ヒント内容をかなり厳密に定義できる。

今回はサンプルとして以下のUserDictクラスを定義した。

class UserDict(TypedDict):
    """Typed User definition."""

    user_name: str
    email: str

このクラスを使うと、どれくらいの型ヒント情報が得られるのかPyCharmを使って検証する。

キーが不足していることを検知できる

まず、インスタンス生成時にキーの指定が不足していることを検知できる。
以下のような初期化はemailキーの初期化が不足していると警告が出る。

user = UserDict(
    user_name='John Due,
)  # Parameter 'email' unfilled

unfilled

なお、このキーの不足の許可はクラス宣言時のTottalyオプション(total=False)でオフにすることもできる。

class Movie(TypedDict, total=False):
    name: str
    year: int

キーの型が間違っていることを検知できる

キーをすべて満たした初期化をしても、間違った型で要素を初期化していると警告される。

user2 = UserDict(
    user_name=20,  # Expected type 'str', got 'int' instead
    email='user@exmaple.com',
)

type error

定義していないキーへの参照を検知できる

TypedDictを使ったクラスのインスタンスに対して、宣言時に定義しなかったキー名を指定すると警告を受ける。
辞書型にするとドットでフィールドを呼び出せなくなるが、これでタイポに気づかずエラーを出してしまうことはないだろう。

print(user['phone'])  # TypedDict "UserDict" has no key 'phone'

key error

Valueの型情報を使って補完ができる

すこし拡張した以下のUserDictを用意する。

from datetime import datetime

class UserDict(TypedDict):
    """Typed User definition."""

    user_name: str
    email: str
    created: datetime
    updated: datetime

createdキーはdatetime型なので、UserDictインスタンスを使ってuser['created'].と書くとそのままdatetime型のメソッド一覧が補完される。

method completion

終わりに

TypedDictは型ヒントなので、違反していても実行は出来てしまうし、IDEを使っていないと恩恵を受けられない。
しかし、Pythonというと「ゆるふわなスクリプト言語」のイメージしかなかったので、ここまで厳密にできるのは驚いた。

参考