[Python] 「TypeError: 'int' object is not iterable」の原因と解決方法

2022年1月9日日曜日

Python

「TypeError: 'int' object is not iterable」の原因と解決方法を紹介します


結論

iterableでないint型のオブジェクトをiterableとして扱おうとしているため発生しているエラーです。
よくあるミスとしてはint型をfor文で回してしまった以下のようなプログラムです。

sample_int = 10
# iterableではないintのオブジェクトをfor文で利用
# TypeError: 'int' object is not iterable
for index in sample_int:
    print(index)

解説

iterableとは

iterableの定義をPython公式ドキュメントの用語集から確認します。

(反復可能オブジェクト) 要素を一度に 1 つずつ返せるオブジェクトです。
反復可能オブジェクトの例には、(list, str, tuple といった) 全てのシーケンス型や、
dictやファイルオブジェクトといった幾つかの非シーケンス型、
あるいはSequence意味論を実装した__iter__()メソッドか__getitem__()メソッドを持つ
任意のクラスのインスタンスが含まれます。


説明だけ聞くとなかなか複雑に思えますが、要はfor文を回せるオブジェクトがiterableです。
list, dict, taple, stringなどがiterableに該当します。
少し意外ですが、stringをfor文で回すと1文字ずつ取得できます。

sample_list = [1, 2, 3]
sample_dict = {'a':1, 'b':2, 'c':3}
sample_taple = {1, 2, 3}
sample_string = 'あいう'

for item in sample_list:
    print(item)
# 1
# 2
# 3

for item in sample_dict:
    print(item)
# a
# b
# c

for item in sample_taple:
    print(item)
# 1
# 2
# 3

for item in sample_string:
    print(item)
# あ
# い
# う

iterableの判断方法

iterableであるか否かはitaratorを生成できるか否かで判断できます。
そのため下記のようなプログラムで判断可能です。

def IsIterable(object):
    '''
    objectがiterableかどうかを判断する
    True:iterable, False:not iterable
    '''
    res = False
    try:
        iterator = iter(object)
        res = True
    except TypeError as te:
        print('This object is not iterable. obj:', object)
        res = False
    return res

sample_list = [1, 2, 3]
sample_float = 1.0

print(IsIterable(sample_list))
# True

print(IsIterable(sample_float))
# This object is not iterable. obj: 1.0
# False

__getitem__()メソッドを持つオブジェクトは必ずしもiterableではない

iterableの定義に下記のような記述があります。

__getitem__()メソッドを持つ任意のクラスのインスタンスが含まれます。

しかし、注意すべきは必ずしもiterableではない点です。
このためhasattr(obj, "__getitem__")で確認すると思わぬ不具合を招きます。

例えば、下記のようなクラスはiterableではありませんが、__getitem__()メソッドを持つオブジェクトです。

class NotIterable:
    def __getitem__(self, str):
        if str == 'a':
            return 1
        if str == 'b':
            return 2
        else:
            raise KeyError

not_iterable = NotIterable()
print(not_iterable['a']) # 1
print(hasattr(not_iterable, '__getitem__')) # True

# __getitem__を持つが反復不可
# KeyError
for item in not_iterable:
    print(item)

一方で、下記のようなクラスはiterableで、__getitem__()メソッドを持つオブジェクトです。

class Iterable:
    def __getitem__(self, int_obj):
        return int_obj * 2

iterable = Iterable()
print(iterable[1]) # 2
print(hasattr(iterable, '__getitem__')) # True

# __getitem__を持つが反復可
for item in iterable:
    print(item)
# 0
# 2
# 4
# 6
# ...

このようにkeyにint以外を定義した場合
__getitem__()メソッドを持つオブジェクトでありながらiterableでないオブジェクトとなります。

AIで副業ならココから!

まずは無料会員登録

プロフィール

メーカーで研究開発を行う現役エンジニア
組み込み機器開発や機会学習モデル開発に従事しています

本ブログでは最新AI技術を中心にソースコード付きでご紹介します


Twitter

カテゴリ

このブログを検索

ブログ アーカイブ

TeDokology