- Python
unhashable type: ‘list’の原因と直し方|Python
TypeError: unhashable type: 'list' は、list を dict のキーや set の要素にしようとしたときのエラーです。 dict のキーと set の要素には、中身が変わらない値(ハッシュ可能な値)しか使えません。list・dict・set は中身を変えられるので使えません。
| エラー文の型 | 置き換える型 |
|---|---|
'list' |
tuple(tuple(リスト)) |
'set' |
frozenset |
'dict' |
frozenset(d.items())、または JSON 文字列 |
| 自作のクラス(dataclass など) | @dataclass(frozen=True) |
確認環境:Python 3.11、pandas 2.2.3・3.0.6(確認日 2026年10月11日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「unhashable type: 'list'の原因と直し方|Python」
再現:エラーになる書き方
| 書き方 | 結果 |
|---|---|
{["東京", "大阪"]: 1}(dict のキーに list) |
unhashable type: 'list' |
{[1, 2], [3]}(set に list) |
unhashable type: 'list' |
set([[1, 2], [1, 2]])(リストのリストの重複を消す) |
unhashable type: 'list' |
[1, 2] in {(1, 2)}(set に list があるか調べる) |
unhashable type: 'list' |
{{"id": 1}: "x"}(dict のキーに dict) |
unhashable type: 'dict' |
{{1, 2}}(set の中に set) |
unhashable type: 'set' |
@lru_cache の関数に list を渡す |
unhashable type: 'list' |
@dataclass のオブジェクトを set に入れる |
unhashable type: 'P' |
{(1, [2, 3]): "x"}(中に list がある tuple) |
unhashable type: 'list' |
in で調べるだけでもエラーになります。 set や dict を調べるときも、内部でハッシュ値を計算するためです。
なぜ list はキーにできないのか
dict や set は、値から計算したハッシュ値で、場所を決めて保存しています。もし list をキーにして、あとで中身を変えると、ハッシュ値が変わり、保存した場所から見つけられなくなります。そのため Python は、中身を変えられる list・dict・set をキーに使わせません。
Python 公式の用語集でも、「変更できないほとんどの組み込みの型はハッシュ可能、変更できるコンテナ(list・dict)はハッシュ可能でない。tuple・frozenset は、中身がすべてハッシュ可能なときだけハッシュ可能」とされています。表の最後の (1, [2, 3]) がエラーになったのはこのためです。
直し方1:list → tuple
counts = {}
key = tuple(["東京", "大阪"]) # ('東京', '大阪')
counts[key] = 1 # OK
リストのリストの重複を消すなら、tuple にしてから dict.fromkeys で、順番を保ったまま消せます。
rows = [[1, 2], [3], [1, 2]]
unique = list(dict.fromkeys(tuple(r) for r in rows))
# [(1, 2), (3,)]
中に list が入った list([[1, [2, 3]]])は、内側も tuple にする必要があります。
直し方2:set → frozenset、dict → frozenset または JSON 文字列
groups = {frozenset({1, 2})} # set の中に set を入れたいとき
# dict をキーにしたいとき(並び順に関係なく同じ dict を同じキーにする)
key1 = frozenset({"id": 1, "a": 2}.items())
key2 = json.dumps({"id": 1, "a": 2}, sort_keys=True) # '{"a": 2, "id": 1}'
| 方法 | 向いている場面 |
|---|---|
frozenset(d.items()) |
値がすべてハッシュ可能(文字列・数値)なとき |
json.dumps(d, sort_keys=True) |
値に list などが入っているとき。sort_keys=True で並び順をそろえる |
直し方3:lru_cache には tuple で渡す
@functools.lru_cache
def total(items):
return sum(items)
total([1, 2, 3]) # TypeError: unhashable type: 'list'
total((1, 2, 3)) # 6
lru_cache は、引数をキーにして結果を覚えるため、引数もハッシュ可能である必要があります。呼び出し側で tuple にして渡します。
直し方4:dataclass は frozen=True
@dataclass
class P:
x: int
{P(1)} # TypeError: unhashable type: 'P'
@dataclass(frozen=True)
class F:
x: int
{F(1), F(1)} # {F(x=1)} ← 同じ値は1つにまとまる
用語集では「自作のクラスのオブジェクトは、既定でハッシュ可能」とされていますが、@dataclass は既定で == での比較を作るため、ハッシュ可能でなくなりました(unhashable type: 'P')。frozen=True にすると、値を変えられない代わりに、set や dict のキーに使えます。
pandas で出るとき
列の値が list(タグ・選択肢の一覧など)だと、pandas の操作で同じエラーになります。
df = pd.DataFrame({"name": ["佐藤", "鈴木", "佐藤"],
"tags": [["A", "B"], ["C"], ["A", "B"]],
"score": [1, 2, 3]})
| 操作 | pandas 2.2.3・3.0.6 |
|---|---|
df.drop_duplicates() |
unhashable type: 'list' |
df.groupby("tags") |
unhashable type: 'list' |
df["tags"].value_counts() |
動く([A, B] が 2、[C] が 1) |
df.drop_duplicates(subset=["name"]) |
動く(list の列を比べないため) |
# list の列を tuple にしてから
df2 = df.assign(tags=df["tags"].apply(tuple))
df2.drop_duplicates(subset=["name", "tags"])
# タグごとに数えたいなら、行を分けてから
df["tags"].explode().value_counts()
# A 2 / B 2 / C 1
explode() は、list の要素ごとに行を分けます。 「タグ A が付いた件数」のように、list の中身で集計したいときに使います。
似たエラー:set を列の指定に使った
df[{"name"}]
# TypeError: Passing a set as an indexer is not supported. Use a list instead.
列を選ぶときは、set({ })ではなく list([ ])で指定します。
確認の手順(チェックリスト)
| 順番 | 確認すること | 方法 |
|---|---|---|
| 1 | どの型か | エラー文の 'list'・'dict'・'set'・クラス名 |
| 2 | どこでキー・set に使っているか | dict のキー、set、in、lru_cache、pandas の groupby・drop_duplicates |
| 3 | 置き換える | list→tuple、set→frozenset、dict→frozenset・JSON 文字列 |
| 4 | tuple の中も確かめる | 中に list があると、tuple でもエラー |
| 5 | 自作のクラス | @dataclass(frozen=True) |
| 6 | pandas | list の列を tuple に、または explode() |
よくある質問
Q. tuple に変えたら、あとで中身を変えられません。 A. キーとして使う値は、変えないのが前提です。中身を変えたいデータは list のまま値の側に持ち、キーには ID や tuple を使います。
Q. JSON から読み込んだデータで出ます。 A. JSON の配列は list、オブジェクトは dict として読み込まれます。それをキーや set に入れるときは、上の方法で tuple・JSON 文字列などに変えます。
まとめ
- list・dict・set は中身を変えられるので、dict のキーや set の要素にできない
- list → tuple、set → frozenset、dict → frozenset(d.items()) か JSON 文字列
- tuple でも、中に list があるとエラー
inでの確認・lru_cacheの引数・@dataclass(frozen なし)でも出る- pandas は list の列で drop_duplicates・groupby が失敗。tuple にするか
explode()
参考・出典
確認日はいずれも 2026年10月11日です。
- Python ドキュメント「Glossary」(hashable):https://docs.python.org/3/glossary.html#term-hashable
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「unhashable type: 'list'の原因と直し方|Python」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。