【2026年9月最新】Pythonのenumerate()でインデックス付きループを完全解説|辞書・zip・パフォーマンスまで
Pythonでリストや辞書をループ処理する際、「要素の値」と一緒に「その要素が何番目にあるか(インデックス)」も欲しくなる場面は非常によくあります。このとき、多くの入門書が紹介するのがenumerate()という組み込み関数です。
しかし、enumerate()の使い方だけを覚えても、「なぜrange(len())ではなくenumerate()を使うべきなのか」「辞書に対して使うとどうなるのか」「zip()と組み合わせるとどう書けるのか」といった、実務で差がつく周辺知識まではなかなか整理されていません。
この記事では、enumerate()の基本構文とstart引数の使い方から、range(len())との比較、辞書・JSONでの活用、zip()との組み合わせ、そして内部動作であるイテレータの仕組みまで、実務で使える形で整理します。最後には、Claude Codeを使ったループ処理のリファクタリングについても紹介します。
01 OVERVIEW enumerate()とは何か インデックスと要素をセットで取り出す組み込み関数
enumerate()は、Pythonの組み込み関数の1つで、リストなどの反復可能なオブジェクト(イテラブル)を渡すと、「インデックス番号」と「要素の値」のペアを順番に返してくれます。
fruits = ['apple', 'banana', 'orange']
for index, fruit in enumerate(fruits):
print(index, fruit)
# 出力:
# 0 apple
# 1 banana
# 2 orange
📚 用語解説
イテラブル(iterable):for文で1つずつ要素を取り出せる(反復処理できる)オブジェクトの総称。リスト・タプル・文字列・辞書・range()の戻り値・ファイルオブジェクトなどが該当する。enumerate()はイテラブルであれば何を渡しても動作するため、リストに限らず辞書や文字列にも使うことができる。
enumerate()を使わずに同じ処理を書こうとすると、以下のようにインデックス用の変数を自分で管理する必要があり、コードが冗長になります。
fruits = ['apple', 'banana', 'orange']
# enumerate()を使わない場合(非推奨)
index = 0
for fruit in fruits:
print(index, fruit)
index += 1
ループの外でindex = 0と初期化し、ループの中でindex += 1としているコードを見かけたら、enumerate()に置き換えられないか検討する価値があります。カウンタの更新忘れやタイミングのズレといったバグの温床を1つ減らせます。
02 BASIC SYNTAX 基本構文とstart引数の使い方 インデックスの開始番号を自由に変更する
2-1. 基本構文
| 引数 | 必須/任意 | 説明 |
|---|---|---|
| iterable | 必須 | ループ対象のリスト・タプル・辞書などのイテラブル |
| start | 任意(デフォルト0) | インデックスの開始番号 |
# 構文
enumerate(iterable, start=0)
2-2. start引数でインデックスの開始番号を変える
デフォルトではインデックスは0から始まりますが、人間が読む一覧表示など「1番目、2番目…」と数えたい場面では、start引数に1を指定すると便利です。
fruits = ['apple', 'banana', 'orange']
for index, fruit in enumerate(fruits, start=1):
print(f'{index}番目: {fruit}')
# 出力:
# 1番目: apple
# 2番目: banana
# 3番目: orange
社内システムやレポートで「No.1、No.2…」のように1始まりの通し番号を表示したい場合、start=1を指定すれば、表示用にわざわざ+1する処理を書かずに済みます。
03 VS RANGE(LEN()) range(len())との比較 なぜenumerate()の方が推奨されるのか
Python初心者が最初に書きがちなインデックス付きループのパターンがrange(len(リスト))を使う方法です。まずは両者を並べて比較してみましょう。
fruits = ['apple', 'banana', 'orange']
# パターンA: range(len())を使う方法
for i in range(len(fruits)):
print(i, fruits[i])
# パターンB: enumerate()を使う方法
for i, fruit in enumerate(fruits):
print(i, fruit)
動作結果はどちらも同じですが、実務ではenumerate()を使う方法が推奨されます。理由は主に3つあります。
| 観点 | range(len()) | enumerate() |
|---|---|---|
| 可読性 | インデックスから毎回要素を取り出す処理が必要で回りくどい | 要素とインデックスを直接受け取れて簡潔 |
| 要素アクセスの手間 | fruits[i]のように配列アクセスが毎回発生する | 値をそのまま変数で受け取れる、アクセス操作が不要 |
| Pythonらしさ | C言語などの伝統的なforループに近い書き方 | Pythonの「イテラブルを直接扱う」思想に沿っている |
📚 用語解説
Pythonic(パイソニック):Pythonの言語設計の思想・慣習に沿った、Pythonらしい書き方を指す言葉。「そのタスクを行うシンプルで明確な方法が1つあるべき」というPythonの設計哲学(The Zen of Python)に基づいており、enumerate()を使う書き方はrange(len())を使う書き方よりPythonicとされることが多い。
インデックスから
毎回配列アクセス
値とインデックスを
直接受け取る
レビューでも
指摘されにくい
range(len())を使ったコードも正しく動作するため、初心者のうちは違いを実感しにくいかもしれません。しかし、チーム開発やコードレビューの現場では、可読性の高いenumerate()を使ったコードの方が「意図が伝わりやすい」と評価される傾向が強く、レビューの指摘事項としてもよく挙がるポイントです。
04 DICT & JSON 辞書・JSONでの活用方法 enumerate()と辞書を組み合わせる際の注意点
enumerate()はリストだけでなく、辞書やJSON(辞書として読み込まれたデータ)にも使えます。ただし、辞書の場合は「何がループされているか」を正しく理解していないと、意図しない結果になるため注意が必要です。
4-1. 辞書に直接enumerate()を使うとキーだけが対象になる
fruit_prices = {'apple': 100, 'banana': 80, 'orange': 120}
for index, key in enumerate(fruit_prices):
print(index, key)
# 出力:
# 0 apple
# 1 banana
# 2 orange
# ※ 辞書を直接forループすると「キー」だけが対象になる仕様のため、
# enumerate()と組み合わせても値(価格)は取得できない
Pythonの仕様上、辞書を直接for文でループするとキーだけが取り出されます。この仕様はenumerate()と組み合わせても変わらないため、「価格も一緒に欲しいのに取れない」という混乱の原因になりがちです。キーと値の両方が必要な場合は、次に紹介する.items()を使います。
4-2. .items()と組み合わせてキー・値の両方を取得する
fruit_prices = {'apple': 100, 'banana': 80, 'orange': 120}
for index, (key, value) in enumerate(fruit_prices.items()):
print(f'{index}: {key} = {value}円')
# 出力:
# 0: apple = 100円
# 1: banana = 80円
# 2: orange = 120円
📚 用語解説
.items():辞書が持つメソッドの1つで、辞書の中身を「(キー, 値)」のタプルの集まりとして取り出す。for key, value in dict.items():のように書くことで、キーと値を同時にループ処理できる。enumerate()と組み合わせる場合は、enumerate(dict.items())のように書き、変数はindex, (key, value)という形でアンパック(分解)して受け取る。
4-3. JSON(ネスト構造)を再帰的に処理する
APIのレスポンスなどで受け取るJSONは、辞書やリストが入れ子(ネスト)になった構造をしていることが多く、単純なenumerate()の1回のループだけでは全要素にインデックスを振れません。ネストしたリストの各階層でそれぞれenumerate()を使う、あるいは再帰関数として実装するのが一般的です。
data = {
'category': 'fruits',
'items': [
{'name': 'apple', 'price': 100},
{'name': 'banana', 'price': 80},
]
}
for index, item in enumerate(data['items']):
print(f"{index}: {item['name']} - {item['price']}円")
# 出力:
# 0: apple - 100円
# 1: banana - 80円
4-4. APIレスポンスのJSONをenumerate()で処理する実践例
実務でよくあるのが、外部APIから取得したJSONレスポンスをPythonの辞書・リストとして読み込み、そのままenumerate()でループしながら加工するケースです。例えば、複数の商品情報が配列で返ってくるAPIを想定してみます。
import json
api_response = '''
{
"products": [
{"id": 101, "name": "ノートPC", "stock": 5},
{"id": 102, "name": "モニター", "stock": 0},
{"id": 103, "name": "キーボード", "stock": 12}
]
}
'''
data = json.loads(api_response)
for index, product in enumerate(data['products'], start=1):
status = '在庫あり' if product['stock'] > 0 else '在庫切れ'
print(f"{index}. {product['name']}(ID:{product['id']}): {status}")
# 出力:
# 1. ノートPC(ID:101): 在庫あり
# 2. モニター(ID:102): 在庫切れ
# 3. キーボード(ID:103): 在庫あり
このように、APIから取得したJSONのリスト部分にstart=1のenumerate()をかけ、表示用の通し番号として使うのは実務でも頻出のパターンです。在庫管理・注文一覧・会員リストなど、「何件目のデータか」を人間に分かりやすく提示したい場面全般に応用できます。
05 WITH ZIP() zip()と組み合わせて複数リストを同時にループする 2つ以上のリストをインデックス付きで並列処理する
複数のリストを同じインデックスで同時に処理したい場合、zip()関数と組み合わせることで、enumerate()の強みをさらに活かせます。
names = ['田中', '佐藤', '鈴木']
scores = [80, 92, 75]
for index, (name, score) in enumerate(zip(names, scores)):
print(f'{index}: {name}さんの得点は{score}点')
# 出力:
# 0: 田中さんの得点は80点
# 1: 佐藤さんの得点は92点
# 2: 鈴木さんの得点は75点
📚 用語解説
zip():複数のイテラブル(リストなど)を受け取り、それぞれの同じ位置の要素同士をタプルとしてまとめる組み込み関数。長さが異なるリストを渡した場合は、最も短いリストの長さに合わせて処理が打ち切られる点に注意が必要。enumerate()と組み合わせることで、「何番目のペアか」を同時に把握しながら複数リストを処理できる。
namesが3件、scoresが2件しかない場合、zip()は短い方(2件)に合わせて処理され、3件目のデータは黙って無視されます。エラーにならないため気づきにくく、データ件数がズレていないか事前にチェックする習慣が重要です。
番号を振りたい
enumerate()単体
両方が欲しい
enumerate(dict.items())
同時に処理したい
enumerate(zip(...))
06 HOW IT WORKS enumerate()の内部動作 イテレータとして実装されている仕組みを理解する
enumerate()をより深く理解するために、その内部動作にも触れておきます。enumerate()は呼び出された時点でリストのようなデータをすべて作るのではなく、enumerateオブジェクトというイテレータを返します。
fruits = ['apple', 'banana', 'orange']
result = enumerate(fruits)
print(result)
# <enumerate object at 0x...> ※中身がまだ展開されていない
print(list(result))
# [(0, 'apple'), (1, 'banana'), (2, 'orange')] ※list()で初めて中身が展開される
📚 用語解説
イテレータ(iterator):要素を1つずつ順番に取り出すための仕組みを持つオブジェクト。イテラブル(リストなど)とは異なり、一度取り出した要素は基本的に再取得できず、また全要素を一度にメモリ上に展開しない「遅延評価」の性質を持つ。enumerate()はこのイテレータとして実装されているため、巨大なリストを扱う場合でもメモリ効率が良い。
この「必要になった分だけ順番に処理する」性質のおかげで、enumerate()は巨大なファイルや大量データを扱う際にもメモリ効率良く動作します。一方で、イテレータであるがゆえの制約もあります。
len()を使うことはできない(要素数が事前に確定していないため)fruits = ['apple', 'banana', 'orange']
result = enumerate(fruits)
for i, f in result:
print(i, f)
# 同じresultをもう一度forに使っても、2回目は何も出力されない
for i, f in result:
print('2回目:', i, f) # 実行されない(イテレータは使い切られている)
enumerate()の戻り値を変数に保存して2回使い回そうとすると、2回目は空扱いになり何も処理されません。複数回ループしたい場合は、都度enumerate(元のリスト)を呼び直すか、一度list(enumerate(元のリスト))としてリスト化してから使い回してください。
07 COMMON MISTAKES よくある間違い・チェックリスト 実装前に確認しておきたいポイント
.items()を忘れている)最後の項目は少し意外に思われるかもしれません。range(len())が明確に必要なケース、例えば「複数のリストを同じインデックスで書き換える必要がある」といった場面では、無理にenumerate()にこだわらず適材適所で選ぶ判断も重要です。
7-1. ループ中の要素削除で起きるインデックスのズレ
numbers = [2, 4, 6, 7, 8]
# 避けたい書き方:ループ中にリストを変更するとインデックスがズレる
for i, n in enumerate(numbers):
if n % 2 == 0:
numbers.pop(i) # 削除によって後続要素のインデックスがズレてしまう
print(numbers) # [4, 7] になる(2, 6, 8は削除できるが、インデックスがズレた影響で偶数の4がチェックされずに生き残ってしまう)
ループしながら元のリストを直接変更すると、enumerate()が返すインデックスと実際のリストの状態がズレてしまいます。安全に書くには、リスト内包表記やfilter()で「削除後の新しいリスト」を作る発想に切り替えるのがおすすめです。
📚 用語解説
リスト内包表記:[式 for 変数 in イテラブル if 条件]という形で、リストを1行で生成できるPythonの構文。ループとif文を使った複数行の処理を簡潔に書き換えられる。ループ中の要素削除で起きるインデックスのズレを避けたい場合、「元のリストは変更せず、条件に合う要素だけを新しいリストとして作り直す」という発想の実装によく使われる。
08 AI-ASSISTED REFACTORING 【独自】Claude Codeを使ったループ処理のリファクタリング 「動いているコード」をPythonicな書き方に近づける
range(len())を多用したコードや、辞書のループでenumerate()を誤用しているコードは、動作している限り放置されがちです。しかし、こうした書き方が積み重なると、コードレビューの手間やチーム内での可読性のばらつきという形でじわじわとコストになっていきます。
ここで実務的に有効なのが、Claude CodeのようなAIコーディングアシスタントに既存のループ処理を見せて、「よりPythonicな書き方に直せないか」を確認しながら改善していく方法です。
| 作業 | AIへの依頼例 |
|---|---|
| range(len())の置き換え | 「このファイル内のrange(len())を使ったループを、enumerate()を使った書き方に直して」 |
| 辞書の誤用チェック | 「辞書に対してenumerate()を使っている箇所で、.items()の付け忘れがないか確認して」 |
| ループ中の削除バグ検出 | 「ループ中にリストを直接変更している箇所を洗い出して、安全な書き方に直して」 |
| 複数リストの並列処理 | 「この2つのループ処理を、zip()とenumerate()を使って1つのループにまとめて」 |
既存のループ処理を
AIに読み込ませる
Pythonicでない
書き方を洗い出す
1箇所ずつ
安全に置き換える
動作確認・
テストで検証
AIに書き換えてもらったコードをそのまま採用するのではなく、「なぜenumerate()の方が良いのか」を毎回質問する習慣をつけると、次に自分でコードを書くときに同じ判断を自力でできるようになります。
09 GENAI CASE STUDY 【独自データ】GENAI社内でのPython活用実例 Claude Max 20xプランでの自動化バッチ処理
弊社(株式会社GENAI)では、Claude Max 20xプラン(月額$200・約30,000円)を契約し、営業・広告運用・記事制作・経理・秘書業務まで、社内のあらゆる業務でPythonスクリプトを活用しています。
| 業務領域 | 主な用途 | 概算削減時間(肌感) |
|---|---|---|
| 広告運用 | 複数媒体のレポートデータを同時に集計するバッチ処理 | 週10h → 週1h |
| ブログ記事 | 記事一覧のインデックス付き検証・進捗管理スクリプト | 1本8h → 1本1h |
| 経理 | 請求書データのリスト処理・仕訳の自動化 | 月40h → 月5h |
こうした自動化スクリプトの中では、複数のデータソース(CSV・API・スプレッドシート)をenumerate()やzip()で同時に処理する場面が頻繁に登場します。基礎的な構文ほど、日々のスクリプトの土台として使われている実感があります。
例えば、複数の広告媒体(Google広告・Meta広告・Yahoo広告など)から取得したレポートデータを1つの週次レポートにまとめる処理では、媒体ごとのCSVを読み込んだリストをzip()でまとめ、enumerate()で通し番号を振りながらSlack通知用のテキストを組み立てる、という流れを日常的に使っています。1件ずつ手作業で表を作っていた頃と比べると、こうした基礎的な構文の積み重ねだけでも、レポート作成にかかる時間は大きく圧縮されました。
上記は弊社の肌感ベースの数値であり、業種・業態・スクリプトの複雑さによって削減時間は変動します。あくまで参考情報としてご覧ください。
10 CONCLUSION まとめ enumerate()を正しく使いこなす
.items()と組み合わせるenumerate()は一見シンプルな関数ですが、start引数・辞書での挙動・イテレータとしての性質まで理解すると、コードの質を一段引き上げられる知識になります。range(len())で「動くコード」を書くことはできても、enumerate()を自然に使いこなせるかどうかは、コードの読みやすさに直結します。
弊社では、こうした基礎的なコーディング習慣の改善から、Claude Codeを活用した業務自動化の設計・伴走支援まで行っています。「社内のコードの書き方を底上げしたい」という方は、ぜひ一度ご相談ください。
Pythonを使った業務自動化・コード品質の底上げも、AI鬼管理が伴走します
enumerate()のような基礎知識の積み重ねが、自動化スクリプト全体の品質を左右します。
AI鬼管理では、Claude Codeを活用した業務自動化の設計から、社内エンジニア以外のメンバーへの定着支援まで対応しています。
ここから先の進め方は、大きく2つあります。
自社で回せるようになりたい方は、AI鬼管理でClaude Code/Codexの使い方から業務設計・社内定着まで伴走を受けながら、社内に仕組みを作る道があります。
覚えるより任せたい方は、AI社員AIKATAでこの記事のような定型業務を丸ごと預ける道があります。料金は月30万円の月額定額、追加費用は0円です。
どちらが合うかは、業務量と社内体制次第です。無料相談・無料適合診断で、貴社の場合はどちらが向くかからご相談いただけます。
NEXT STEP
この記事の内容を、あなたのビジネスで
実践してみませんか?
よくある質問
Q. enumerate()とrange(len())はどちらを使うべきですか?
A. 基本的にはenumerate()が推奨されます。要素の値とインデックスを直接受け取れるため可読性が高く、配列アクセス(リスト[インデックス])の手間も省けます。range(len())は、複数のリストを同じインデックスで書き換える必要があるなど、特定の場面でのみ使うのが実務的です。
Q. enumerate()を辞書に使うとどうなりますか?
A. Pythonの仕様上、辞書を直接forループするとキーだけが対象になるため、enumerate()と組み合わせても「インデックスとキー」しか取得できません。キーと値の両方を取得したい場合は、enumerate(辞書.items())のように.items()と組み合わせる必要があります。
Q. enumerate()のstart引数はどんなときに使いますか?
A. 人間が読む一覧表示で「1番目、2番目…」のように1から数えたい場合に便利です。start=1を指定すれば、表示のたびにインデックスへ+1する処理を書かずに済みます。
Q. enumerate()とzip()は一緒に使えますか?
A. 使えます。enumerate(zip(リスト1, リスト2))のように書くことで、複数のリストを同じインデックスで同時にループ処理できます。ただしzip()はリストの長さが異なる場合、短い方に合わせて打ち切られる点に注意してください。
Q. enumerateオブジェクトを2回使い回すことはできますか?
A. できません。enumerate()はイテレータとして実装されており、一度forループやlist()で中身を取り出すと使い切られてしまいます。再度ループしたい場合は、都度enumerate(元のリスト)を呼び直すか、事前にlist(enumerate(...))としてリスト化しておく必要があります。
Q. ループ中にenumerate()で取得したインデックスを使ってリストを削除してもいいですか?
A. 避けるべきです。ループ中に元のリストの要素を削除すると、後続要素のインデックスがずれてenumerate()の挙動と実際のリストの状態が食い違い、意図しない結果になります。削除が必要な場合は、リスト内包表記などで「削除後の新しいリスト」を作る書き方に切り替えてください。
Claude Codeで業務自動化を90日で叩き込む
経営者向けの伴走型パーソナルトレーニング
AI鬼管理/AI社員AIKATAへのお問い合わせ
この記事を読んで気になった方へ。
専門スタッフが、御社に最適な
業務自動化・業務代行プランを無料でご提案します。




