【Python型ヒント】Optional型の本当の意味知ってる?Noneを許容する正しい使い方
こんにちは。ゆうせいです。
Pythonで型ヒントを使い始めると、コードの安全性がぐっと高まり、読みやすくもなりますよね。name: str や age: int のように、変数や関数の引数がどんな型を持つべきかを明示するのは、もはや現代的な開発の常識です。
ですが、こんな時どうすれば良いか迷ったことはありませんか? 🤔
「ユーザーをIDで検索する関数を作ったけど、もし見つからなかったら None を返したい…」
この「文字列を返すかもしれないし、None を返すかもしれない」という状況を、型ヒントでどう表現すれば良いのでしょうか。その答えこそが、今回ご紹介する typing モジュールの Optional 型です!
None が返る可能性のある、よくあるケース
まず、具体的なコードで考えてみましょう。
ユーザーIDをキー、ユーザー名を値として持つ辞書から、ユーザーを検索する関数を作ります。
# ユーザーデータを辞書で代用
users_db = {
1: "Sato",
2: "Suzuki",
3: "Takahashi",
}
# IDが見つかればユーザー名(str)を、見つからなければNoneを返す関数
def find_user_by_id(user_id: int): # -> ???
return users_db.get(user_id)
この find_user_by_id 関数の返り値の型ヒント (-> の後ろ) は、何と書くのが正しいでしょうか?
-> str と書いてしまうと、「この関数は必ず文字列を返します」という嘘をつくことになります。IDが見つからなかった場合に None が返ってくると、型ヒントと実際の振る舞いが食い違ってしまい、バグの原因になってしまいます。
救世主 Optional の登場 ✨
ここで登場するのが Optional です。typing モジュールからインポートして使います。
from typing import Optional
# ユーザーデータを辞書で代用
users_db = {
1: "Sato",
2: "Suzuki",
3: "Takahashi",
}
def find_user_by_id(user_id: int) -> Optional[str]:
return users_db.get(user_id)
# 実際に使ってみる
user_name = find_user_by_id(2) # Suzuki
not_found = find_user_by_id(99) # None
print(user_name)
print(not_found)
返り値の型ヒントを -> Optional[str] と書くことで、「この関数は、文字列(str)または None を返します」という意味を正確に表現できます。これで、関数の使い方を見ただけで、返り値が None になる可能性を考慮すべきだと一目で分かりますね!
Optional型の正体は Union
実は、Optional 型には秘密があります。それは、Optional[X] という書き方が、Union[X, None] という書き方の、ただの別名(エイリアス)だということです。
Union は、複数の型を取りうることを示す型ヒントです。つまり、Union[str, None] は「文字列または None」という意味で、Optional[str] と完全に同じなのです。Optional は、この None を許容するケースが非常によく使われるため、特別に用意された便利なショートカットというわけですね。
よくある誤解: 「任意引数」との違い ⚠️
Optional という名前から、「関数の引数を任意にする(省略可能にする)ためのものだ」と誤解してしまうことがありますが、これは間違いです!
- 任意引数 (Optional Argument): 引数にデフォルト値を設定し、呼び出し時に省略できるようにすること。def greet(name: str = "Guest"): ...
- Optional型 (Optional Type): 変数や返り値が、特定の型または None のどちらかをとりうると示すこと。-> Optional[str]
この二つは全く異なる概念なので、混同しないように注意しましょう!
Optionalを使う最大のメリット: バグの事前検知
Optional を使う最大のメリットは、コードの意図が明確になることに加え、None に起因するエラーを未然に防げることです。
find_user_by_id(99) の結果が None であることを忘れて、次のようなコードを書いてしまったとします。
user_name = find_user_by_id(99)
print(user_name.upper()) # 大文字にしようとする
これを実行すると、AttributeError: 'NoneType' object has no attribute 'upper' という、誰もが一度は見たことのあるエラーが発生します。
しかし、MyPyのような静的解析ツールを使うと、コードを実行する前にこの問題を検知してくれます。user_name は Optional[str] 型なので None の可能性があるため、「None でないことをチェックせずに .upper() を呼び出すのは危険ですよ!」と警告してくれるのです。
安全なコードは、次のように書きます。
user_name = find_user_by_id(99)
if user_name is not None:
# このブロックの中では、user_nameがstrであることが保証される
print(user_name.upper())
else:
print("ユーザーが見つかりませんでした。")
この一手間が、信頼性の高いソフトウェアを作る上で非常に重要になります。
これからの学習に向けて
Optional[X] は、「値が X 型または None の可能性がある」ことを示す、非常に重要な型ヒントです。
関数が None を返す可能性がある場合や、変数が初期状態で None を持つ場合には、積極的に Optional を使っていきましょう。この習慣が、あなたのコードをより安全で、他の開発者にとっても親切なものに変えてくれます。
型ヒントの世界は奥が深いですが、まずは Optional を使いこなし、None にまつわるエラーを撲滅することから始めてみてくださいね! 👍
セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク
投稿者プロフィール
- 代表取締役
-
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。
最新の投稿
山崎講師2025年10月27日重回帰分析はディープラーニングの「細胞」だった?"ご先祖様"と"最強の進化系"のつながりを徹底解剖
山崎講師2025年10月27日機械学習の"ご先祖様"?重回帰分析が今も最強の「基礎」である理由
山崎講師2025年10月27日ディープラーニングの「常識」を疑え!相関分析が“無力”に見える理由と、それでも使うべき本当の価値
山崎講師2025年10月27日相関分析は最強の「データスカウト」!機械学習の精度を上げる”相棒”の正体とは