概要
IndexError: list index out of range
エラーに遭遇し、このエラーを出ないようにするor捕捉してあげることでエラーをキャッチできるコードを3つ作成したので紹介します。
list index out of range
とは
以下のコードを実行すると、リストの最初の要素のfruit_name
を取得できます。
def get_first_data_of_list(data, key, sub_key):
value = ''
if key in data:
if sub_key in data[key][0]:
value = data[key][0][sub_key]
return value
information = {
"fruit":
[
{"fruit_name" : "apple",
"fruit_price" : "200" },
{"fruit_name" : "banana",
"fruit_price" : "100" }
],
}
value = get_first_data_of_list(information, "fruit", "fruit_name")
print(value) # apple
しかし、information
データの中身が空で連携された場合、結果はどうなるでしょうか。
def get_first_data_of_list(data, key, sub_key):
value = ''
if key in data:
if sub_key in data[key][0]:
value = data[key][0][sub_key]
return value
information = {
"fruit":[],
}
value = get_first_data_of_list(information, "fruit", "fruit_name")
print(value) # apple
結果は以下。
if sub_key in data[key][0]:
IndexError: list index out of range
上述の通り、list index out of range
というインデックスエラーになってしまいました。
このエラーは、リストのインデックスの範囲外、存在しない値を使用して要素にアクセスしようとすると発生するエラーです。空のリストで何も要素がないのに、if sub_key in data[key][0]
で1番目のインデックスにアクセスしようとしているため、「範囲外のインデックス」として上述のエラーが発生しました。
もっとわかりやすい例で言うと、以下のように、「範囲外のインデックス」の場合はこのエラーが発生します。
lst = [1, 2, 3]
print(lst[3])
空のリストでもエラーにならないコード1
以下のようにすると、空のリストが連携されてもエラーになりません。
これは、data[key][0]
にアクセスする前に、data[key]
がリストであることかつその長さが0より大きいことを条件としています。これにより、空のリストでもエラーが発生しないようにすることができます。
def get_first_data_of_list(data, key, sub_key):
value = ''
if key in data and isinstance(data[key], list) and len(data[key]) > 0:
if sub_key in data[key][0]:
value = data[key][0][sub_key]
return value
information = {
"fruit":[],
}
value = get_first_data_of_list(information, "fruit", "fruit_name")
print(value) # apple
空のリストでもエラーにならないコード2
以下のコードでも、空のリストでエラーになりません。
def get_first_data_of_list(data):
try:
return data.get('fruit', [{}])[0].get('fruit_name', '')
except IndexError:
return ''
information = {
"fruit":[],
}
value = get_first_data_of_list(information)
print(value)
このコードでは、get
メソッドを使用して辞書からキーに対応する値を取得しています。get
メソッドの第二引数は、キーが辞書に存在しない場合に返されるデフォルト値を指定します。
エラーについては、try/except
ブロックを使用して例外を捕捉してあげる形にしています。
空のリストでもエラーにならないコード3
以下は、Pythonの組み込み関数next
とジェネレータ式を使用して実現しているコードです。
def get_first_fruit_name(data):
fruits = data.get('fruit', [])
return next((item.get('fruit_name', '') for item in fruits if 'fruit_name' in item), '')
information = {
"fruit":[],
}
value = get_first_fruit_name(information)
print(value)
ジェネレータはあまり使ったことがないですが、大量のデータを扱う場合や大量にfor
ループを繰り返す際には、メモリを節約することができるらしいです。リスト全体をメモリにロードするのではなく、一度に1つの要素だけを生成するからですね。
上記では、next
関数を使用して、fruit_name
キーを持つ最初の辞書のfruit_name
の値を取得。
next
関数の第二引数は、ジェネレータが終了した(=fruit_name
キーを持つ辞書がない)場合に返されるデフォルト値を指定します。
参考:ジェネレータとnext
関数の参考例
2の倍数を無限に生成するジェネレータ式から、一つずつ次の要素を取り出すコード:
gen = (i * 2 for i in range(100))
print(next(gen)) # 0を出力
print(next(gen)) # 2を出力
print(next(gen)) # 4を出力