閉じる

【Python】辞書のキー存在確認完全方法|in・get・例外処理まで解説

Pythonの辞書(dict)を扱うとき、キーの存在確認はとてもよく登場します。

シンプルなin演算子からgetメソッド、そしてKeyErrorを使った例外処理まで、状況に応じた「正しい選び方」ができると、コードは読みやすく安全になります。

本記事では、初心者の方にも分かりやすいように、図解とサンプルコードを交えながら詳しく解説します。

辞書のキー存在確認の基本

dictにキーが存在するか確認する理由

Pythonの辞書でキーの存在確認をする最大の理由は「エラーを防ぎ、安全に値を取り出すため」です。

辞書は「キー」から「値」を取り出すデータ構造です。

例えばユーザー情報を辞書で持っている場合を考えます。

Python
user = {
    "name": "Taro",
    "age": 20
}

print(user["name"])  # "name"キーの値を取得

このとき、存在しないキーを指定するとKeyErrorが発生します。

Python
user = {
    "name": "Taro",
    "age": 20
}

print(user["email"])  # "email"キーは存在しない
実行結果
Traceback (most recent call last):
  File "sample.py", line 6, in <module>
    print(user["email"])
KeyError: 'email'

このように、辞書から値を取り出す前にキーの存在を確認しておくと、不要なエラーを防ぎ、プログラムを安全に動かすことができます

また、キーの存在確認は次のような場面でも重要です。

  • オプション項目(例: プロフィールの自己紹介文)があるかどうかをチェックしたいとき
  • 設定ファイルで、指定されたキーがあるかどうかを検証したいとき
  • APIレスポンス(JSON)で、特定のフィールドが送られているかどうか確認したいとき

このように、辞書のキー存在確認は、日常的なPythonプログラミングの中で頻繁に登場します。

Pythonの辞書(dict)でキーを扱う際の注意点

辞書のキーは「存在するかどうか」だけでなく、「どのような型をキーにしているか」「値がNoneのときどう扱うか」も意識する必要があります。

辞書のキーを扱うときに注意したいポイントを、いくつか整理します。

キーと値の「存在」と「中身」を混同しない

キーが存在するかどうかと、値が空かどうかは別問題です。

Python
data = {
    "name": "Taro",
    "nickname": None,
}

print("nickname" in data)  # True
print(data["nickname"])    # None
実行結果
True
None

キー"nickname"は存在しているが、その値がNoneである、という状態です。

そのため、「値がNoneだからキーが存在しない」と判断してしまうと、バグの原因になります。

値を見て存在確認しない

次のような書き方は、意図しない動作を生みがちです。

Python
data = {
    "count": 0
}

if data.get("count"):
    print("countがあります")
else:
    print("countがありません")
実行結果
countがありません

これは0が「偽」と判定されるためです。

「キーが存在するか」を知りたいときはin、値の有無(空文字や0など)を判定したいときは別途条件を書くように意識するとよいです。

ハッシュ可能なオブジェクトしかキーにできない

辞書のキーにできるのは、ハッシュ可能(immutable)なオブジェクトに限られます。

代表的なものは次の通りです。

  • 利用できる: strintfloattuple(要素もハッシュ可能な場合) など
  • 利用できない: listdictset など

誤ってリストなどをキーにしようとすると、エラーになります。

Python
d = {}
d[[1, 2, 3]] = "NG"
実行結果
TypeError: unhashable type: 'list'

辞書でキーを扱うときは、「存在確認」「値の中身」「キーの型」を明確に区別して考えることが大切です。

in演算子を使ったキー存在確認

in演算子によるキー存在確認の書き方

辞書のキー存在確認の最も基本的な方法がin演算子です。

構文はとてもシンプルで、キー in 辞書と書くだけで、そのキーが存在するかTrue/Falseで返ってきます。

Python
user = {
    "name": "Taro",
    "age": 20
}

print("name" in user)   # True
print("email" in user)  # False
実行結果
True
False

図解: in演算子によるキー存在確認のイメージ

図の通り、in演算子は辞書の「キー」だけを見て存在確認を行います

値は確認していない点に注意してください。

if文とinを使った典型的なコード例

辞書のキー存在確認は、実際のコードではif文と組み合わせて使うことがほとんどです。

Python
user = {
    "name": "Taro",
    "age": 20
}

# "email"キーがあるかチェックしてから値を取り出す例
if "email" in user:
    # キーが存在するときだけ値を使う
    print("メールアドレス:", user["email"])
else:
    print("メールアドレスは登録されていません")
実行結果
メールアドレスは登録されていません

このようにif キー in 辞書という形で、安全に値を取り出せます。

少し応用した例も見てみます。

Python
config = {
    "timeout": 10,
    "retries": 3,
}

# オプション設定をキー存在で分岐させる例
if "timeout" in config:
    print("タイムアウト:", config["timeout"], "秒")
else:
    print("デフォルトのタイムアウト値を使います")

if "log_level" in config:
    print("ログレベル:", config["log_level"])
else:
    print("ログレベルはINFOを使用します")
実行結果
タイムアウト: 10 秒
ログレベルはINFOを使用します

値を取り出すときはif キー in dictdict[キー]をセットで使う、というパターンは非常に頻出です。

in演算子のメリット・デメリット

メリット

1. シンプルで読みやすい "key" in dという形は直感的で、Pythonに慣れていない人にも意味が伝わりやすいです。

2. 値を見ないので誤判定が少ない inはあくまで「キーの有無」だけを判定するため、0""Noneなど、値が「偽」になるケースに影響されません。

3. パフォーマンスが良い(平均O(1)) 辞書のキー検索はハッシュテーブルを使っているため、平均して非常に高速です。

多くの場面でinはパフォーマンス面でも有利です。

デメリット

1. 存在確認と値取得が分かれる if "key" in d:で存在を確認し、その後でd["key"]で値を取り出す必要があります。

「存在確認+値取得」を1行で済ませたい場合はgetの方が向いています

2. デフォルト値を返す処理が書きにくい 「キーがなければこの値を使う」というロジックを書くとき、inだけだと若干まわりくどくなります。

Python
if "timeout" in config:
    timeout = config["timeout"]
else:
    timeout = 10

このような場合、getを使うとすっきり書けます。

詳しくは次の章で説明します。

getメソッドでのキー存在確認とデフォルト値

dict.getでキー存在確認と値取得を同時に行う方法

dict.get()は、キーの存在確認と値の取得を同時に行える便利なメソッドです。

基本の構文は次の通りです。

  • dict.get(key)
  • dict.get(key, default)

キーが存在する場合は、その値を返します。

存在しない場合は、第二引数で指定したdefaultを返します(省略したときはNoneを返します)。

Python
user = {
    "name": "Taro",
    "age": 20
}

print(user.get("name"))   # "Taro"
print(user.get("email"))  # None (デフォルト)
実行結果
Taro
None

図解: getメソッドの動き

この図のように、getはキーがなくてもKeyErrorを発生させず、安全にNoneやデフォルト値を返してくれます

getメソッドでデフォルト値を返すパターン

第二引数にデフォルト値を指定することで、「キーがないときの値」を簡単に設定できます。

Python
config = {
    "timeout": 10
}

timeout = config.get("timeout", 30)  # あればその値、なければ30
mode = config.get("mode", "debug")  # あればその値、なければ"debug"

print("timeout:", timeout)
print("mode:", mode)
実行結果
timeout: 10
mode: debug

もしキー"mode"が存在しない場合でも、"debug"が返されます。

この書き方は、「存在すればその値、なければこの値」という処理を1行で書けるため、設定値やオプション値を扱う場面でとてもよく使われます。

dict.getとif文を組み合わせる例

getで取得した値を、そのままif文で判定するパターンもよくあります。

Python
params = {
    "q": "python dict",
    # "page" は省略されることがある
}

page = params.get("page", 1)  # ページ番号、省略時は1ページ目

if page == 1:
    print("最初のページです")
else:
    print(page, "ページ目です")
実行結果
最初のページです

このように、「なければ1を使う」「なければ空文字を使う」「なければ空リストを使う」などを簡潔に書けるのがgetの大きな魅力です。

inとgetの使い分けのポイント

「キーの存在そのものを知りたいのか」「値が欲しいのか」で使い分けると考えると分かりやすくなります。

代表的な使い分けを表にまとめます。

目的推奨方法説明
キーが存在するかどうかだけ知りたい"key" in d真偽値だけ分かればよい場合。
キーがあれば値を使い、なければ別の値を使いたいd.get("key", default)設定値やオプション処理に最適。
キーがなければエラーにしたい(必須項目など)d["key"]または例外処理強制的にKeyErrorを発生させて不正データを検出する。

具体的な判断基準

  • 存在フラグが欲しいだけ
    if "email" in user: のようにinを使う
  • 「あれば使う、なければデフォルト」を1行で書きたい
    timeout = config.get("timeout", 30) のようにgetを使う
  • キーがなければ「それはエラーにすべき」仕様
    → わざとd["key"]KeyErrorを起こすか、後述する例外処理を使う

inは「存在チェック専用」、getは「値取得とデフォルト適用」、角括弧[]は「必須キー」を表す、と覚えておくと使い分けやすくなります。

例外処理(KeyError)を使ったキー存在確認

try-exceptでKeyErrorを捕捉する方法

「キーがなければエラーにしたいが、エラーを自分でハンドリングしたい」という場合に使うのが、try-exceptによるKeyErrorの捕捉です。

基本形は次のようになります。

Python
user = {
    "name": "Taro",
    "age": 20
}

try:
    # 必須とみなすキーを角括弧で取得
    email = user["email"]
    print("メールアドレス:", email)
except KeyError:
    # キーが存在しない場合の処理
    print("メールアドレスが設定されていません")
実行結果
メールアドレスが設定されていません

このように、存在しないキーを角括弧[]でアクセスしたときに発生するKeyErrorを、自分でキャッチして分岐処理を書くことができます。

例: 必須キーと任意キーを分ける

Python
user = {
    "name": "Taro",
    # "email" は任意
}

try:
    # nameは必須項目なので、なければエラーとみなす
    name = user["name"]
    print("ユーザー名:", name)
except KeyError:
    raise ValueError("ユーザー名(name)は必須です")

# emailは任意項目として扱う
email = user.get("email", "(未登録)")
print("メールアドレス:", email)
実行結果
ユーザー名: Taro
メールアドレス: (未登録)

この例では、必須キーは角括弧アクセス+KeyErrorで厳しくチェックし、任意キーはgetでゆるく扱う、という使い分けをしています。

例外処理を使ったパフォーマンスと注意点

パフォーマンスの観点

Pythonでは「例外は通常のフローとして多用しない」のが一般的なスタイルです。

理由の1つは、例外処理は通常の処理よりコストが高いからです。

大量ループの中で、キーが存在しないことが頻繁に起こる場合try-exceptKeyErrorを連発させると、パフォーマンスに悪影響が出る可能性があります。

そのため通常は次のような方針がおすすめです。

  • 「キーがあることがほぼ確実」なとき:
    → 角括弧[]で直接アクセスし、万が一のために外側で1回だけ例外処理をする
  • 「キーがないこともよくある」場合:
    ingetで事前に確認し、例外を乱発させない

可読性の観点

例外処理は強力な仕組みですが、多用するとコードの流れが追いにくくなります。

例として、次の2つの書き方を比べてみます。

Python
# 例1: inでチェックするパターン
if "timeout" in config:
    timeout = config["timeout"]
else:
    timeout = 30
Python
# 例2: 例外処理でチェックするパターン
try:
    timeout = config["timeout"]
except KeyError:
    timeout = 30

どちらも同じ意味ですが、「ただ存在チェックしたいだけ」であれば、例外処理を使わずingetで書く方が読みやすいことが多いです。

in・get・例外処理の使い分けまとめ

ここまで紹介した3つの方法を、「意図」と「コード量」「エラー処理の方針」という観点から整理します。

方法向いている場面特徴
in「キーの有無」だけを知りたいとき真偽値でシンプルに判定。値取得は別途角括弧[]で行う。
get「存在すればその値、なければデフォルト」を使いたいとき1行で書けて読みやすい。KeyErrorを発生させない。
try-except KeyError「必須キーがなければエラー」という仕様を明示したいときエラー処理を細かく制御できるが、多用すると読みにくくなる。

簡易的な指針

  • 存在チェックだけならin
    例: 「このオプションが指定されているか?」
  • 値+デフォルトが欲しいならget
    例: 「指定されていなければ10秒にする」
  • 必須項目で、なければ例外にしたいなら[]+例外処理
    例: 「ユーザーIDがないレスポンスは不正として扱う」

この3つを場面ごとに正しく使い分けられると、辞書まわりのコードは一気に読みやすく、安全になります。

まとめ

本記事では、Pythonの辞書におけるキーの存在確認について、in演算子、getメソッド、KeyErrorを用いた例外処理の3つの方法を解説しました。

「キーの有無だけを知りたいならin」「値とデフォルトをまとめて扱うならget」「必須項目を厳格に扱うなら例外処理」という使い分けを意識すると、実務でも迷いにくくなります。

辞書のキー存在確認はあらゆるPythonコードで登場する基礎ですので、今回の内容を土台に、実際のプロジェクトでも積極的に活用してみてください。

リスト・辞書・セット

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!