エラーの内容
関数の戻り値、データベースの行、APIレスポンスなど、何かをループ処理しようとしたときに、Pythonが次のエラーを投げることがあります:
TypeError: 'NoneType' object is not iterable
つまり、Noneに対してイテレートしようとしたということです。forループ、リスト内包表記、タプルのアンパック、*スプレッドなど、Pythonのすべてのイテレーション機構は実際のイテラブルを必要とします。Noneはイテラブルではありません。
最も簡単な再現方法はこちらです:
def get_users():
pass # returnを書き忘れた
for user in get_users(): # ここでTypeError
print(user)
根本原因
明示的なreturn文を持たないPython関数は、暗黙的にNoneを返します。これは言語仕様であり、バグではありません。ただし、同じ落とし穴を引き起こすパターンが他にもいくつかあります:
- 考慮していない分岐で関数が
Noneを返す場合 — たとえば、対応するelseのないif文など list.sort()やdict.update()などのインプレースメソッドはオブジェクトを変更してNoneを返す — 常に- ORMクエリ、データベースカーソル、またはAPI呼び出しが、結果セットが空の場合に
Noneを返す - そういったインプレースメソッドの戻り値を変数に代入してしまう
最後のパターンは開発者が頻繁にはまる罠です。具体的にはこのような形になります:
items = [3, 1, 2]
items = items.sort() # sort()はソート済みリストではなくNoneを返す!
for item in items: # TypeError: 'NoneType' object is not iterable
print(item)
itemsは今やNoneです。元のリストはソートされていますが、その参照を捨ててしまったのです。
修正方法
修正1:関数が実際に何を返すかを確認する
ループの前に、値を出力または確認します:
result = get_users()
print(type(result), result) # デバッグ:実際に何が得られたか確認
出力が<class 'NoneType'> Noneであれば、関数が期待通りの値を返していません。該当箇所を見つけてreturn文を追加してください:
def get_users():
users = db.query("SELECT * FROM users")
return users # 以前は抜けていた
修正2:明示的なNoneチェックでガードする
Noneが正当な結果となる場合もあります — 結果なし、処理対象なし。イテレートする前にガード処理を入れましょう:
users = get_users()
if users is not None:
for user in users:
print(user)
または1行にまとめることもできます:
for user in (users or []):
print(user)
or []はusersがNoneのときに空のリストで代替します。ループは0回実行され、例外も発生しません。
修正3:関数内でデフォルトの空コレクションを返す
呼び出し箇所ごとに修正するのは手間がかかります。関数を一度だけ修正しましょう:
def get_users():
result = db.query("SELECT * FROM users")
if result is None:
return [] # 常にリストを返す
return result
呼び出し元は自由にイテレートできます。各使用箇所でガード処理を書く必要はありません。
修正4:インプレースメソッドの代入の罠を修正する
list.sort()、list.reverse()、dict.update()、set.add()はいずれもインプレースで変更を行い、Noneを返します。その戻り値を代入しないでください:
# 間違い
items = items.sort()
# 正しい:インプレースでソートし、参照を維持する
items.sort()
# または sorted() を使う — 新しいリストを返す
items = sorted(items)
修正5:チェーン呼び出しのNoneを処理する
メソッドチェーンはNoneを隠蔽し、後になって爆発します。これは危険です:
# response.json()がNoneを返す可能性がある
for item in response.json().get("results"):
process(item)
分解して各ステップで確認してください:
data = response.json()
results = data.get("results") if data else []
for item in (results or []):
process(item)
修正6:セイウチ演算子(Python 3.8以降)
関数が外部のもので戻り値の型を変更できない場合、セイウチ演算子は2行のチェックよりもすっきりと書けます:
if (users := get_users()) is not None:
for user in users:
print(user)
Noneの発生源を探す
トレースバック全体を読んでください。Pythonは正確な行を特定してくれます:
Traceback (most recent call last):
File "app.py", line 12, in process_orders
for order in get_orders(user_id):
TypeError: 'NoneType' object is not iterable
12行目に移動してください。イテラブルはget_orders(user_id)です。その上にデバッグ出力を追加します:
result = get_orders(user_id)
print(f"get_orders returned: {result!r}")
for order in result:
...
!rフォーマットは値に対してrepr()を呼び出します。None、空文字列''、空リスト[]を明確に区別できます — repr出力ではこれらの3つはすべて異なる表示になります。
動作確認
修正後にコードを再実行してください。TypeErrorが発生しなければ成功です。ガードパスがNoneを正しく処理することを確認するには、明示的にシミュレーションします:
def get_users():
return None # 結果なしをシミュレート
users = get_users()
for user in (users or []):
print(user)
print("Done — no error")
期待される出力:
Done — no error
ループ本体はスキップされます。例外も発生しません。これが望ましい動作です。
予防策
- 型ヒントを追加する:
def get_users() -> list[User]:は期待される戻り値の型を文書化します。mypyを実行すると、Noneを返すコードパスにフラグを立ててくれます。 Optionalを正直に使う:関数が正当にNoneを返す可能性がある場合は、Optional[list]とアノテーションしてください。これにより呼び出し元に「イテレートする前に確認してください」というシグナルを送れます。- インプレースメソッドの戻り値を代入しない:
sort()、reverse()、update()、append()— これらはすべてNoneを返します。頭に叩き込んでおきましょう。 - Noneではなく空のコレクションを返す:リストを取得する関数は、空の結果のとき
Noneではなく[]を返すべきです。Noneは「この値が存在しない」という意味に留めましょう — 「何も見つからなかった」ではありません。

