【Python】TypeError: ‘NoneType’のエラー原因と対処法まとめ(初心者向け・実例でわかりやすく解説)

Python-prograshi(プロぐらし)-kv Python
記事内に広告が含まれていることがあります。

再帰関数などを使って処理を記述している場合に、次のようなエラーが発生することがあります。

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を設置

以上で無事に処理が動きます。

タイトルとURLをコピーしました