【備忘録】Pythonで型定義を付けるだけでコードが格段に読みやすくなる話

Python

皆さん、こんにちは!
上越市を拠点にし、「FA設備・装置開発」と「画像処理」に強い会社、NSIです!
私達は豊富な経験と専門知識で、各種業界の自動化・システム化のお手伝いをしています。

1月は「今季最強の寒波」などと言われ、大雪が降ったり降らなかったりと、天候に振り回される日々でした。
やっと道路が走りやすくなったと思った矢先、翌日にはまた雪…なんてことも。
2月に入りましたが、まだまだ気は抜けません。雪解けが待ち遠しいですね。

今回は、Pythonで型定義を付けるとコードが読みやすくなる話 について書いていこうと思います。

はじめに

皆さん、Python使ってますか?
Pythonはシンプルで読みやすく、学習コストが低い言語で、以下のような特徴があります。

  • 文法が分かりやすく、直感的に書ける
  • インタプリタ言語のため、実行時に型が決まる
  • セミコロンや型宣言が不要

言語特有のルールが少なく、初見でもサクッと書けるのがPythonの魅力ですが、業務で継続的に使っていく場合、いくつか注意点もあります。型宣言がないため、一度お客さんへリリースしたあと、数ヶ月ぶりにソースを見返すと、「この関数の引数って、どんなデータ型だっけ?」となることがあります。また、引数の数さえ合っていれば何でも渡せてしまうため、誤った値を指定したまま、実行時に気付く…なんてこともあったりします。

変数名に型の名前を含めるなどの工夫をすればある程度はカバーできますが、コードが冗長になったり、命名に悩む原因になったりしてしまいます。

C#やJavaのように型宣言できないのかな…と思っていたところ、実はPythonでも型定義を書けるとの情報を耳にしたので、今回まとめてみることにしました。

型定義を書いてみよう

早速、型定義の有無でどれだけ読みやすさが変わるか比較してみましょう!

例1. 足し算をする関数

【型定義なし】

def add(a, b):
    return a + b

・aとbが何なのか分からない(数値?文字列?リスト?)
・呼び出す側が、関数の実装を見ないと使い方を判断できない

【型定義あり】

def add(a: int, b: int) -> int:
    return a + b

・引数と戻り値の型が一目で分かる
・エディタの補完や型チェックの恩恵を受けやすくなる

例2. 辞書を参照する関数

【型定義なし】

def get_user_name(user):
    return user["name"]

・user がどのような構造のデータなのか分からない
・想定しているキーや値の型がコードから読み取れない

【型定義あり】

from typing import Dict

def get_user_name(user: Dict[str, str]) -> str:
    return user["name"]

・キー値ともに文字列の辞書であることが明確になる
・想定と異なる型を渡してしまうミスに気付きやすくなる

例3. ファイルを読み込む関数

【型定義なし】

def load_file(path):
    with open(path) as f:
        return f.read()

・path が文字列なのか Path オブジェクトなのか判断できない
・戻り値が文字列なのか、バイナリなのかが分からない

【型定義あり】

from pathlib import Path

def load_file(path: Path) -> str:
    with path.open() as f:
        return f.read()

・ファイルパスとして Path オブジェクトを受け取る関数だと分かる
・戻り値が文字列であることが明確になる

型定義は万能ではない

型定義を書くことで、関数がどのような意味を持っているかが分かりやすくなりました。
ここまで見ると、「型定義を書けば、間違った型を渡したときにエラーになるのでは?」と思う方もいるかもしれません。

しかし、Pythonの型定義は、実行時の挙動には一切影響しません。
型定義を書いていても、実行時には型チェックは行われず、間違った型を渡してもそのまま処理が進みます。例えば、次のようなコードがあった場合…

def add(a: int, b: int) -> int:
    return a + b

add("10", "20")

このコードは実行時エラーにはならず、文字列として結合されて “1020” が返ります。
型定義はあくまで「人やツール向けの情報」であり、Python自体が型の正しさを保証してくれるわけではないため、注意してください。

それでも型定義を書く意味

実行時にチェックされないと聞くと、「それなら意味がないのでは?」と思うかもしれません。
しかし、型定義の本当の価値は 実行前に気付けること にあります。

型定義を書くことで、エディタの補完が効き、使い方を間違えにくくなることや、コードを読むだけで、前提条件や意図が伝わるなどの恩恵が得られます。(以下はVSCodeのエディタ画面です。)

実際の業務では、リリース後の保守や追加改修を別の担当者が行うことも多く、コードの意図がきちんと伝わるかどうかは重要なポイントになります。つまり、型定義は バグを防ぐための仕組みというより、バグを作りにくくするための仕組み と言えます。

べんぞうくん
べんぞうくん

型定義は次に触る人のための説明書!

最後に

今回は「Pythonで型定義を付けるとコードが読みやすくなる話」についてご紹介しました。
コードを記述する際に、1つ気を付けるだけで可読性や保守性がぐっとアップします。
チーム開発する場合にも有効なので、皆さんもぜひ使ってみてはいかがでしょうか?

ここまで読んでいただき、ありがとうございました。
ご質問・ご要望・ご相談などは、下記お問い合わせフォームからお気軽にご連絡ください。
https://www.net-nsi.co.jp/toiawase.html

べんぞうくん
べんぞうくん

この記事になるほど!と思ったらいいねを押してね~

タイトルとURLをコピーしました