【Pythonエラー解決】TypeError: unhashable typeって何?辞書のキーに使えないものの正体

こんにちは。ゆうせいです。

Pythonでデータを扱う上で、辞書(dictionary)は本当に便利ですよね!キーバリューをペアで管理できるので、プログラムの色々な場面で大活躍します。

文字列や数字をキーにすることは、みなさんよくやっていると思います。ですが、こんな風に考えたことはありませんか?

「リストをキーにできないかな?」

「もし使ったら、どんなエラーが出るんだろう?」

実は、Pythonの辞書のキーには「使えるもの」と「使えないもの」に明確なルールが存在します。このルールを知らないと、TypeError: unhashable type という、一見すると謎のエラーに遭遇してしまうかもしれません。

今回は、この辞書のキーに関するたった一つの大事なルールを、例え話を交えながら徹底的に解説していきます!


結論:辞書のキーは「変更不可能なもの」しか使えない!

いきなり結論からいきましょう。辞書のキーにできるもののルールは、たった一つです。

それは、「イミュータブル(immutable)であること」

…いきなり専門用語が出てきましたね。大丈夫、難しくありませんよ!

「イミュータブル」とは、ひと言でいうと「一度作ったら、中身を変更できない」という性質のことです。

たとえるなら、一度現像した「写真」のようなものです。写真に写っている人や風景を、後から変えることはできませんよね。これがイミュータブルのイメージです。

逆に、中身を自由に変えられる性質のことを「ミュータブル(mutable)」と言います。こちらは「ホワイトボード」を想像してください。書いたり消したり、自由に内容を変更できます。

Pythonの主なデータ型をこの2種類に分けると、以下のようになります。

イミュータブルな型(キーに使える!)

  • int (整数)
  • float (浮動小数点数)
  • str (文字列)
  • bool (真偽値 True, False
  • tuple (タプル)

ミュータブルな型(キーに使えない!)

  • list (リスト)
  • dict (辞書)
  • set (セット)

そう、キーに使えないものの代表格はリスト、辞書、セットなんです。


なぜ?キーが変更不可能でなければならない理由

「でも、なんでそんなルールがあるの?」と思いますよね。その理由を理解することが、エラーを根本から解決する一番の近道です!

Pythonの辞書は、目的のデータを非常に高速に見つけ出す仕組みを持っています。その秘密が「ハッシュ値」というものです。

ハッシュ値とは、データから計算される、そのデータを表すための「指紋」のようなものだと考えてください。Pythonは、辞書にデータを追加するとき、キーの「指紋(ハッシュ値)」を計算し、その指紋とデータを関連付けて保管します。

そしてデータを取り出すときは、指定されたキーの指紋を再度計算し、「この指紋のデータはどこかな?」と一瞬で探し当てるのです。

ここで、もしキーが変更可能(ミュータブル)だったらどうなるでしょう?

リスト [1, 2] をキーとして辞書に登録したとします。Pythonは [1, 2] の指紋を計算してデータを保管します。

しかし、その後であなたが my_list.append(3) のようにリストの中身を [1, 2, 3] に変えてしまったら…?

大変です!指紋の元となるデータが変わってしまったので、もう同じ指紋は作れません。Pythonは「あれ?最初に登録された指紋のデータが見つからない!」と大混乱に陥ってしまいます。

まるで、合鍵を作ったのに、後から家の鍵穴の形が変わってしまったようなものです。もう二度と家には入れませんよね。

このような大混乱を防ぐために、Pythonは「指紋が変わってしまう可能性のあるもの(=ミュータブルな型)は、キーとして登録できません!」という厳しいルールを設けているのです。

そして、このルールを破った時に表示されるのが、あのエラーメッセージです。

TypeError: unhashable type: 'list'

これは直訳すると「リストという型は、ハッシュ化(指紋を計算)できません」という意味だったのですね。


実際に試してみよう!

ルールが分かったところで、実際にコードで確認してみましょう。

キーとして使える例

# 文字列、整数、タプルはイミュータブルなのでOK
ok_dict = {
    "name": "Yusei",
    100: "Price",
    (10, 20): "Coordinate"
}

print(ok_dict)

キーとして使えない例(エラー発生)

# リストはミュータブルなのでNG
ng_list = [1, 2, 3]

try:
    ng_dict = {ng_list: "This will fail"}
except TypeError as e:
    print(f"エラーが発生しました: {e}")

実行結果:

エラーが発生しました: unhashable type: 'list'

見事にTypeErrorが発生しましたね!


まとめと今後の学習指針

今回の内容をまとめます。

  • 辞書のキーになれるのはイミュータブル(変更不可能)な型だけ。
  • なぜなら、Pythonはキーのハッシュ値(指紋)を使ってデータを高速管理しているから。
  • キーの中身が変わるとハッシュ値も変わり、データを見失ってしまうため。
  • リスト、辞書、セットはミュータブル(変更可能)なのでキーには使えない。
  • TypeError: unhashable type は「そのデータ型はハッシュ化できませんよ」というサイン。

この「イミュータブル」と「ミュータブル」の区別は、Pythonプログラミングにおいて非常に重要な概念です。関数の引数で意図せず値が書き換わってしまう問題など、他の場面でもこの知識があなたを助けてくれるでしょう。

もし「リストをどうしてもキーのように使いたい!」という状況になったら、一度タプルに変換する tuple(my_list) ことを検討してみてください。タプルはイミュータブルなので、キーとして安心して使えますよ。

データ型の性質をしっかり理解して、エラーを恐れず、さらにPythonの世界を楽しんでいきましょう!

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。