pythonは動的型付け言語ですが、バージョン3.5で型ヒントが導入されたことにより、静的型付け言語っぽく開発することができるようになりました。

ただし、公式ページ にも以下のように書いてあるように、

Python ランタイムは、関数や変数の型アノテーションを強制しません。 型アノテーションは、型チェッカー、IDE、linterなどのサードパーティーツールで使われます。

型ヒント自体はあくまでコメントの延長であり動作には一切影響を与えません。型チェッカー、IDE、linterなどのツールによって利用されます。

型ヒントの導入に関してはメリットしかないと思いますので、導入して快適なpython lifeをおくりましょう。

型ヒントのメリット

型ヒントを導入するメリットは3つあると思います。

  1. コードチェック
  2. 入力候補の表示
  3. 可読性向上

コードチェック

型ヒントの最大のメリットは静的型チェックだと思います。
IDEで実装中に、ファイルを保存時に型ヒントで指定した型と異なる型の値がアサインされている場合にエラーになります。

ただし、VSコードの場合、コードチェックはデフォルトのままではやってくれないので、mypyを導入し、settings.jsonに以下のように設定します。

{
    "python.linting.lintOnSave": true,
    "python.linting.mypyEnabled": true,
}

なお、コードチェックツールをいれない場合、実装が正しくて型ヒントだけが間違っている状態でコードがcommitされる可能性があります。
その場合、型ヒントは誤解を生むだけなので、可読性が下がることになります。型ヒントを導入するのでれば、コードチェックツールは必ず導入した方がいいです。

入力候補の表示

型ヒントを指定してくことで、IDEが変数の型を認識し、その変数が持っているプロパティや関数をプルダウンで表示してくれます。
VSコードを使っていれば、これはデフォルトでやってくれるようです。

可読性向上

正しく型ヒントを書いてある場合、可読性が著しく向上します。

例えば、

books = library.get_books_by_name('xxx')

とあったして、booksに入る型がListなのかSetなのか、何のリストなのかを明確に判断できる人はいないと思いますが、

books: Set[Book] = library.get_books_by_name('xxx')

となっていれば、誰がみてもBookのSetであることが理解できます。

同様に、

@dataclasses.dataclass(frozen=True)
class Liblary:
    all_books
    def get_books_by_name(self, name):
        return set(filter(lambda b:b.name == name, self.all_books))

とあったとして、このnameの型が何なのか、戻り値がListなのかSetなのか、Setだとしてどの型のSetが返るのかを正確に判断するのは困難だと思いますが、

@dataclasses.dataclass(frozen=True)
class Liblary:
    all_books: Set[Book]
    def get_books_by_name(self, name: str) -> Set[Book]:
        return set(filter(lambda b:b.name == name, self.all_books))

となっていれば、引数も戻り値も誰の目から見ても明確になります。

型ヒントを書いて欲しい場所

もともとJavaの世界からプログラミングをスタートした自分としては、全ての箇所に型ヒントを書くのが一番いいと感じますが、kotlinやscalaなど型推論が導入されている言語もあり全てに型を記載することがデメリットに感じることも理解できます。
例えば、何かのライブラリを使う場合に、途中段階で生成する変数の型を全部調べ上げるのはあまり意味がない気もします。
なので、絶対に型ヒントを書いて欲しい場所だけ記載しておきます。

  • 関数の引数と戻り値
  • クラスのプロパティ
  • グローバル変数

その他Tips

型ヒントの実装方法自体はいろんな記事が世の中にあるので、ここでは自分がムムッと思った点だけTipsとして残しておきます。

ListやSetなどの型ヒントの書き方

pythonの組み込み型であってもそのままでは型ヒントをかけないものが結構あります。
その場合はtypingモジュールから必要な型をimportして使ってください。

# 型をimportする必要がある
from typing import List, Dict, Tuple, Set

set: Set[str] = set()
list: List[str] = []

[2020/10/23 追記] python3.9から組み込み型は個別にimportしなくても型ヒントに使えるようになったそうです。こちらを参照。

for文の変数には型ヒントは使えない

以下のようなケースでfor文の変数にstrという型を指定しようとしても、SyntaxErrorで怒られます。

for word: str in get_words():
    print(word)