TypeError: ‘NoneType’ object is not subscriptable とは
Pythonで開発をしていると、突如として「TypeError: ‘NoneType’ object is not subscriptable」というエラーに遭遇することがあります。これは、リストや辞書のように要素にアクセスできるオブジェクトを期待していた場所で、予期せずNoneが渡されてしまった時に発生します。

このエラー、Python初心者だけでなくベテランでもうっかりやっちゃいますよね!原因を特定するのに時間がかかってしまうこともあります。
実行環境ごとのエラーメッセージ
| 環境 | エラーメッセージ |
|---|---|
| Python 3.x | TypeError: 'NoneType' object is not subscriptable |
エラーの発生パターン
このエラーは主に以下のようなケースで発生します。
パターン1: 関数やメソッドが期待する値を返さずNoneを返しているケース
def get_user_data(user_id):
# 実際はデータベースからユーザーデータを取得する想定
if user_id == 1:
return {'name': 'Alice', 'age': 30}
# user_idが1以外の場合、明示的なreturnがないためNoneが返る
user = get_user_data(2)
# userはNoneType
print(user['name']) # TypeError: 'NoneType' object is not subscriptable
get_user_data関数は、user_idが1の場合のみ辞書を返します。それ以外のuser_idでは、明示的なreturn文がないため、Pythonは自動的にNoneを返します。 その結果、user変数にはNoneが代入され、Noneに対して辞書のキーアクセスを行おうとしてエラーが発生します。
def get_user_data(user_id):
if user_id == 1:
return {'name': 'Alice', 'age': 30}
# 期待するデータがない場合は空の辞書や特定の値を返す
return {}
user = get_user_data(2)
# userは空の辞書
# アクセスする前に辞書が空でないか、キーが存在するかを確認する
if user:
print(user.get('name', 'N/A')) # get()メソッドで安全にアクセス
else:
print("ユーザーデータが見つかりませんでした。")
パターン2: 辞書のキーが存在しないのに直接アクセスしようとしているケース
config = {'database': 'mydb', 'user': 'admin'}
# 'password'キーは存在しない
print(config['password']) # KeyErrorが発生するはずだが...
# ...しかし、実際にはdict.get()のデフォルト値の処理ミスなどでNoneが入るケースが多い
# 例: 何らかの処理でconfig['password'] = None となってしまった後
config_with_none = {'database': 'mydb', 'user': 'admin', 'password': None}
# NoneTypeの値をさらにサブスクリプトしようとする
# これは直接 TypeError にはならないが、後の処理で問題を起こす例
# password_length = len(config_with_none['password']) # TypeError を引き起こす可能性がある
# より直接的な例: 辞書のget()メソッドでデフォルト値がNoneのままさらにアクセス
def get_setting(key):
settings = {'host': 'localhost'}
return settings.get(key) # 'port'は存在しないのでNoneが返る
port = get_setting('port') # portはNone
# port[0] のように None に対してアクセスしようとするとエラー
# ここでは例として単純なNoneTypeオブジェクトへのアクセスを再現
def process_value(value):
return value[0] # Noneが来ると TypeError になる
# portはNoneなので TypeError: 'NoneType' object is not subscriptable が発生
# process_value(port)
Pythonの辞書で存在しないキーに直接アクセスするとKeyErrorが発生しますが、このエラーは何らかの理由でキーの値が明示的にNoneに設定された後、そのNoneをリストや辞書のように扱おうとした場合に発生します。 または、dict.get(key, default=None)のようにデフォルト値がNoneのまま、存在しないキーにアクセスした結果がNoneとなり、そのNoneに対してさらに操作を行おうとした場合にも発生します。
config = {'database': 'mydb', 'user': 'admin'}
# dict.get()メソッドでデフォルト値を指定して安全にアクセス
# キーが存在しない場合は指定したデフォルト値が返る
password = config.get('password', 'default_password')
print(f"Password: {password}")
# Noneが返る可能性がある場合は、Noneチェックを行う
def get_setting_safe(key):
settings = {'host': 'localhost'}
return settings.get(key) # 'port'は存在しないのでNoneが返る
port = get_setting_safe('port')
if port is not None:
# Noneでないことが保証されるため安全に処理できる
print(f"Port: {port}")
else:
print("ポート設定が見つかりませんでした。")
パターン3: APIレスポンスや設定ファイルなど、ネストされたデータ構造の解析ミス
import json
# ユーザー情報が欠落している可能性のあるJSONデータ
json_data = '''
{
"status": "success",
"data": {
"id": 123,
"name": "Charlie"
# "address"キーが欠落している
}
}
'''
response = json.loads(json_data)
# 'address'キーが存在しないため、response['data'].get('address') は None を返す
# そのNoneに対してさらに['city']でアクセスしようとしている
city = response['data'].get('address')['city']
print(city) # TypeError: 'NoneType' object is not subscriptable
外部からのAPIレスポンスや設定ファイルなど、ネストされたデータ構造を扱う際によく発生します。 この例では、response['data']には'address'キーが存在しないため、response['data'].get('address')はNoneを返します。その返されたNoneに対して、さらに['city']でアクセスしようとした結果、TypeErrorが発生しています。
import json
json_data = '''
{
"status": "success",
"data": {
"id": 123,
"name": "Charlie"
}
}
'''
response = json.loads(json_data)
# ネストされたキーにアクセスする際は、Noneチェックを挟むか、安全なアクセス方法を使う
address = response['data'].get('address')
if address:
city = address.get('city')
print(f"City: {city}")
else:
print("Address情報が見つかりませんでした。")
# もしくは、よりPythonicな書き方として、walrus operator (Python 3.8+) も利用可能
# if (address := response['data'].get('address')):
# city = address.get('city')
# print(f"City: {city}")



特にAPIレスポンスの処理で、ネストが深いとどこがNoneなのか見つけにくいんですよね〜。落ち着いてデバッグすることが解決への近道です。
よくあるバリエーション
APIレスポンスで 'NoneType' object is not subscriptable が発生する
外部APIからのJSONレスポンスをパースする際、期待するキーが存在しないためにdict.get()がNoneを返し、そのNoneに対してさらにネストされたキーにアクセスしようとするとこのエラーになります。APIの仕様変更やデータ欠損が原因で発生します。
import json
# 悪い例: 'user_info'キーがない場合
response_data_bad = '{"status": "ok", "data": {}}'
parsed_data_bad = json.loads(response_data_bad)
# user_infoはNoneになる
# user_name_bad = parsed_data_bad.get('data').get('user_info')['name']
# 良い例: 各段階でNoneチェックまたはデフォルト値指定
response_data_good = '{"status": "ok", "data": {"user_info": {"name": "Bob"}}}'
parsed_data_good = json.loads(response_data_good)
data_section = parsed_data_good.get('data', {})
user_info = data_section.get('user_info', {})
user_name_good = user_info.get('name', 'Unknown')
print(f"User Name: {user_name_good}")
'NoneType' object is not subscriptable がリスト操作で発生する
リストから要素を取り出す際に、リストが空であるか、または存在しないインデックスにアクセスしようとしてNoneが返され、そのNoneに対してさらにインデックス操作を行うと発生します。 例えば、next()関数でデフォルト値を指定しなかった場合などが考えられます。
# 悪い例: 空のリストに対して first() 関数が None を返す想定
def get_first_element(items):
# 実際にはリストが空だと IndexError になるが、ここではNoneTypeを引き起こす状況を模倣
if not items:
return None
return items[0]
my_list_bad = []
first_item_bad = get_first_element(my_list_bad)
# print(first_item_bad[0]) # first_item_badはNoneなので TypeError
# 良い例: Noneチェックを行う
my_list_good = []
first_item_good = get_first_element(my_list_good)
if first_item_good is not None:
print(first_item_good)
else:
print("リストは空です。")
フレームワーク別の発生パターン
Django (ORM QuerySet)での発生パターン
DjangoのORMで.first()や.get()メソッドを使用する際、条件に一致するオブジェクトが見つからなかった場合にNoneが返されることがあります。そのNoneに対して、さらに属性アクセスを行おうとすると、このエラーが発生します。
from myapp.models import User
# ID=999のユーザーは存在しないと仮定
user = User.objects.filter(id=999).first()
# userはNoneType
# print(user.username) # TypeError: 'NoneType' object is not subscriptable
# 修正例
if user is not None:
print(user.username)
else:
print("ユーザーが見つかりません。")
Pandas (DataFrame/Series)での発生パターン
PandasのDataFrameやSeriesで特定の条件でデータを抽出したり、locやilocで存在しないインデックスにアクセスしようとしたりした場合に、結果がNoneや空のSeries/DataFrameになることがあります。その後に続く処理で、Noneに対してリストや辞書のようにアクセスしようとすると発生します。
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
# 存在しない列 'C' を選択しようとする (結果は KeyError になることが多いが、
# 特定の操作で None が返ってきてしまうケースも想定)
# df['C'][0] # KeyError
# より直接的な例: applyなどでNoneを返し、その結果にアクセス
def get_value_or_none(row):
if row['A'] == 100: # 存在しない条件
return {'val': 10}
return None
# result_series は None が含まれる可能性
# result_series = df.apply(get_value_or_none, axis=1)
# 以下のような状況で発生しやすい:
# フィルタリングの結果が空になり、その後の処理でNoneTypeにアクセス
filtered_df = df[df['A'] == 100] # 空のDataFrame
# filtered_df.iloc[0] は KeyError や IndexError を出すが、
# 例えば何らかの関数が None を返すような場合を想定
def get_first_element_or_none(data_frame):
if not data_frame.empty:
return data_frame.iloc[0]
return None
first_row = get_first_element_or_none(filtered_df)
# print(first_row['A']) # first_row は None なので TypeError
根本原因の特定方法
このエラーに遭遇したら、まずエラーが発生している行の直前にある変数の値と型を確認しましょう。print()関数やロギング、またはIDEのデバッガを使って、エラーの原因となっている変数がいつNoneになったのかを特定することが最も効果的です。
def process_data(data_id):
# データを取得する関数。id=100以外ではNoneを返すとする
if data_id == 100:
return {'item': 'apple', 'price': 100}
print(f"DEBUG: Data not found for id {data_id}, returning None.")
return None
my_data = process_data(200)
# デバッグポイント: my_dataの値と型を確認
print(f"DEBUG: my_data value is {my_data}")
print(f"DEBUG: my_data type is {type(my_data)}")
# エラーが発生する行
# item_name = my_data['item'] # ここで TypeError が発生する
PythonにおけるNoneTypeの特殊性とFalse相当性
PythonのNoneは、値が存在しないことや、操作が結果を返さなかったことを示す特別なオブジェクトです。他の言語のnullに相当しますが、PythonではNoneTypeという専用の型を持ち、シングルトン(唯一のインスタンス)として扱われます。 また、if None:はFalseと評価されるため、条件分岐で簡単にチェックできます。しかし、オブジェクトの属性や要素にアクセスしようとする場合は、明示的にif variable is not None:とチェックすることが重要です。
防止策とベストプラクティス
このエラーを防ぐ最も確実な方法は、変数がNoneになる可能性がある箇所を特定し、アクセスする前にNoneチェックを行うことです。 辞書には.get()メソッドを使い、デフォルト値を指定するのも非常に有効です。Python 3.5以降の型ヒントも、開発段階で潜在的なNoneの問題を発見するのに役立ちます。
from typing import Optional, Dict, Any
def fetch_user_settings(user_id: int) -> Optional[Dict[str, Any]]:
# ユーザー設定を取得する関数
if user_id == 1:
return {'theme': 'dark', 'notifications': True}
return None
user_id_to_fetch = 2
settings = fetch_user_settings(user_id_to_fetch)
# NoneTypeエラーの予防策
if settings is not None:
print(f"Theme: {settings.get('theme', 'light')}") # .get()で安全にアクセス
else:
print("ユーザー設定が見つかりませんでした。")



Optional型ヒントは、開発中にNoneTypeエラーを未然に防ぐ強力な味方です。ぜひ活用して、安全なコードを書きましょう!



落ち着いて変数の値を確認する。これ、どんなエラー解決にも共通する鉄則ですね!焦らず一つずつ見ていきましょう!
よくある質問(FAQ)
-
Q本番環境でだけ『NoneType’ object is not subscriptable』が発生する原因は何ですか?
-
A
本番環境でのみ発生する場合、開発環境とデータソースや環境設定の違いが主な原因です。例えば、本番DBにしかないデータ欠損、APIの呼び出し制限、環境変数(例: APIキー)の未設定などが
Noneを返す原因となっている可能性があります。
-
QPythonの
Noneと他の言語のnullは同じですか? -
A
概念的には非常に似ていますが、厳密には異なります。Pythonの
Noneは唯一のNoneTypeオブジェクトであり、is Noneで等価性をチェックします。他の言語のnullは、言語によってundefinedやnilなど様々な形で実装されており、その振る舞いも異なります。
-
QLinterや静的型チェッカーでこのエラーを事前に防ぐ方法はありますか?
-
A
はい、可能です。Pythonの型ヒント(Type Hinting)を積極的に利用し、MyPyのような静的型チェッカーをCI/CDに組み込むことで、
Noneになる可能性がある変数を早期に検出し、開発段階で修正できます。
-
Q辞書のキーアクセスで
dict['key']とdict.get('key')のどちらを使うべきですか? -
A
キーの存在が確実な場合は
dict['key']で問題ありません。しかし、キーが存在しない可能性がある場合は、dict.get('key', default_value)を使うべきです。.get()はキーが存在しない場合にdefault_value(指定がなければNone)を返すため、KeyErrorを防ぎつつ、NoneTypeエラーも予防できます。
-
Qエラー発生時にユーザーにどのようなメッセージを表示すべきですか?
-
A
ユーザー向けには、技術的なエラーメッセージをそのまま表示するのではなく、「システムエラーが発生しました。時間をおいて再度お試しください」のような、分かりやすく丁寧なメッセージを表示するべきです。バックエンドでは
try-exceptブロックでエラーを捕捉し、ログに詳細を記録することで、ユーザー体験を損なわずにデバッグ情報を得られます。
この記事と一緒に知っておきたい用語
| 用語 | この記事との関連 |
|---|---|
| NULL | PythonではNoneがNULLに相当し、エラーの原因になりやすい |
| デバッガ | エラー原因の特定にデバッガの活用が有効 |
| コンパイルエラー | 実行時エラーとの違いを理解するとデバッグが効率化する |
| DRY原則 | コード重複を避けることでエラーの発生箇所を絞りやすくなる |


コメント