再帰関数などを使って処理を記述している場合に、次のようなエラーが発生することがあります。
TypeError: 'NoneType' object is not iterable
なお、この記事の内容は、上記以外でも「NoneTpye」を含むエラー全般の発生原因と対処法にもなっています。
・can only concatenate list (not "NoneType") to list
・can't multiply sequence by non-int of type 'NoneType'
・unsupported operand type(s) for +: 'NoneType' and 'list'
など、、、
結論
最初に結論を述べると、主な原因は次の2つです。
①戻り値(return)のない関数の実行結果は「値None, タイプNoneType」になる。
②関数を変数に代入する場合は、その関数にreturnがあること。
└ printではだめ。(実行結果ではなく、実行途中のいち処理のため)
└ returnは関数の最終出力となっていること。
└ 関数内のどこかにreturnが1個あればいいというわけではない。
以下で実例を踏まえて原因と対処法について解説しています。
エラーが発生する状況例
例えば、次のように多次元配列からintを抜き出そうとしたときに、’NoneType’ object is not iterableのエラーが発生します。
arr0 = [1,[2],[[3]]]
def number(arr):
result=[]
if isinstance(arr, int):
result.append(arr)
if isinstance(arr, list):
#要素を一つずつ抜き出す
for brr in arr:
res = number(brr)
result += res #←ここがエラー
return result
number(arr0)
#出力
TypeError: 'NoneType' object is not iterable
問題点
‘NoneType’のオブジェクトをいじろうとしていることが原因です。
▼もう少し細かく
「res = number(brr)」で変数に関数number()代入しているが、この関数自体に戻り値(return)がないため、変数にはNoneが格納され、タイプがNoneTypeとなっている。
「result += res」このNoneTypeの変数resと、list型の変数resultを結合しようとしたため、
resはイテラブルじゃないから結合できないと言われている。
NoneTpyeとは
関数にデフォルト引数が渡されなかった場合に発生するエラー。値はNoneのみとのこと。
(python公式)Noneとは
型 NoneType の唯一の値です。 None は、関数にデフォルト引数が渡されなかったときなどに、値の非存在を表すのに頻繁に用いられます。 None への代入は不正で、SyntaxError を送出します。
▼簡単にするとこんな感じ
関数の実行結果が空とき、その結果自体がNoneTypeになる。
なので、実行結果が空の関数を変数に代入するとNoneTypeになる。
def hello():
pass
x = hello()
print(type(x))
print(x)
#出力
<class 'NoneType'>
None
printの場合もNoneTypeになる
def hello():
print("こんにちは")
x = hello()
print(type(x))
#出力
こんにちは
<class 'NoneType'>
「こんにちは」が出力されているが、関数の実行過程で表示されたもので、関数自体と置き換わるものではない。
対処法(returnの設置)
NoneTypeとしないために、returnで関数に実態をもたせる。
└ 戻り値(return)は関数を実行した結果を関数自身と置き換える。
def hello():
return ("こんにちは")
x = hello()
print(type(x))
print(x)
#出力
<class 'str'>
こんにちは
xが文字列「こんにちは」に置き換わっている。
returnの設置場所の注意点
関数の中にreturnがあればいいというわけではありません。実行した最終結果としてreturnを経由する必要があります。
▼returnが記述されているがNoneTypeになる例
def hello(n):
if n > 2:
return ("こんにちは")
x = hello(1)
print(type(x))
print(x)
#出力
<class 'NoneType'>
None
1 < 2 のため、関数の出力結果は空になっている。この原因は、returnの処理を経由しないためです。
▼実行結果がreturnを経由する場合はOK
def hello(n):
if n > 2:
return ("こんにちは")
x = hello(3)
print(type(x))
print(x)
#出力
<class 'str'>
こんにちは
補足
▼関数自体はのタイプはfunction
def hello():
print("こんにちは")
print(hello)
#出力
<function hello at 0x00000222AE142160>
▼関数自体を変数に代入する場合はカッコ不要
def hello():
return ("こんにちは")
x = hello #←カッコ不要
print(type(x))
print(x)
#出力
<class 'function'>
<function hello at 0x00000222AE1423A0>
▼変数(関数を代入)の実行例
def hello(n):
if n > 2:
return ("こんにちは")
x= hello
print(x(3))
#出力
こんにちは
hello()=x()となっている。
対処結果
冒頭に記述したエラーコードを修正すると以下のようになります。
ポイントは、変数に代入する値が関数にならないよう、returnを適切に設置する。
def number(arr):
result=[]
if isinstance(arr, int):
result.append(arr)
if isinstance(arr, list):
#要素を一つずつ抜き出す
for brr in arr:
res = number(brr)
result += res
return result #←関数numberの戻り値としてresultを設置
以上で無事に処理が動きます。