【Python初心者】「イテラブル」と「イテレータ」の違いを図と実例で解説

Pythonの勉強をしていると、<strong>イテラブル（Iterable）</strong>と<strong>イテレータ（Iterator）</strong>という言葉が頻繁に出てきます。

しかしこの2つ、名前が似ていて非常に混乱しやすいものです。  
この記事では、両者の違いを初心者にも分かるように、実例を交えながらわかりやすく解説します。

## イテラブルとイテレータの違い【ざっくりまとめ】

| 用語       | 意味                                 | 持っているメソッド                  | 例                        |
|------------|--------------------------------------|-------------------------------------|---------------------------|
| イテラブル (Iterable) | `for`文で回せるオブジェクト              | `__iter__()`                       | リスト、文字列、辞書など |
| イテレータ (Iterator) | `next()` で1つずつ値を取り出せるオブジェクト | `__iter__()` と `__next__()` を両方持つ | `iter(リスト)` など      |

## iter() / next() の正体と内部のしくみ

イテラブルとイテレータは、以下のような関数やメソッドで動いています。

### 1. iter(obj)

- イテラブル（リストや文字列など）からイテレータを作る関数  
- 実際には `obj.__iter__()` が呼ばれます

### 2. next(obj)

- イテレータから次の要素を取り出す関数  
- 実際には `obj.__next__()` が呼ばれます

### 3. __iter__()

- イテラブルが持つメソッドで、`iter()` によって呼ばれる

### 4. __next__()

- イテレータが持つメソッドで、`next()` によって呼ばれる  
- 要素が尽きたら `StopIteration` を送出します

| 名前             | 分類     | 説明                               | 誰が使う？         |
|------------------|----------|------------------------------------|--------------------|
| `iter(obj)`      | 関数     | `obj.__iter__()` を呼んでイテレータを返す | ユーザー（呼び出し側） |
| `next(obj)`      | 関数     | `obj.__next__()` を呼んで値を返す         | ユーザー            |
| `__iter__()`     | 特殊メソッド | `iter()` によって呼び出される             | オブジェクトの中身（開発者） |
| `__next__()`     | 特殊メソッド | `next()` によって呼び出される             | オブジェクトの中身（開発者） |

## イメージで理解する：イテラブルとイテレータの関係図
```py
[10, 20, 30]   ← イテラブル（データの箱）
    ↓ iter()
<iterator>     ← イテレータ（1個ずつ取り出すマシン）
    ↓ next()
10
20
30
```
## 実際のコードで違いを確認してみよう
```py
lst = [10, 20, 30]  # イテラブル
it = iter(lst)      # イテレータを作成

print(next(it))  # 10
print(next(it))  # 20
print(next(it))  # 30
print(next(it))  # StopIteration 発生
```
> 🔸 **補足：** `next()` は要素が尽きると `StopIteration` という例外を発生させます。  
> この例外は `for` 文の内部でも使われており、ループの終了条件として自動的にキャッチされます。

### hasattr を使って確認
```py
print(hasattr(lst, '__iter__'))   # True（イテラブル）
print(hasattr(lst, '__next__'))   # False（イテレータではない）

print(hasattr(it, '__iter__'))    # True（イテレータはイテラブルでもある）
print(hasattr(it, '__next__'))    # True（イテレータ）
```

:::note info
#### 補足：hasattrとは？

`hasattr()` は、あるオブジェクトが特定の「属性（メソッドや変数など）」を持っているかどうかを確認する組み込み関数です。  
`True` または `False` を返します。
```py
    hasattr(オブジェクト, '属性名')
```
※属性名は **文字列で渡す必要があります**

##### 例：イテラブルとイテレータの判定
```py
lst = [1, 2, 3]
it = iter(lst)

print(hasattr(lst, '__iter__'))   # True（繰り返し可能なオブジェクト）
print(hasattr(lst, '__next__'))   # False（nextでは取り出せない）

print(hasattr(it, '__iter__'))    # True（イテレータは自身もイテラブル）
print(hasattr(it, '__next__'))    # True（nextで要素が取り出せる）
```
このように `hasattr()` を使えば、対象が「イテラブルか」「イテレータか」を簡単に確認できます。
:::

## イテラブル・イテレータの使われ方（用途別）

### イテラブルが使われる場面

| シーン                       | 説明                                      |
|----------------------------|------------------------------------------|
| `for` 文での繰り返し処理     | `for x in リスト:` のように使用           |
| 組み込み関数の処理対象       | `list()`, `sum()`, `sorted()` などに渡せる |
| メンバー確認                 | `x in イテラブル` のような使い方          |
| zip(), enumerate() などで使う | 要素を同時に処理・番号付き処理が可能       |

### イテレータが使われる場面

| シーン                         | 説明                                      |
|--------------------------------|------------------------------------------|
| `next()` で1個ずつ取り出したいとき | 明示的に順番に処理する                   |
| `for` 文の裏側                  | for文は内部でイテレータを使っている      |
| メモリ効率を重視した処理         | 巨大データを一気に読み込まない処理に便利 |
| ファイルやストリームの読み取り    | 一行ずつ処理するなど                     |

## まとめ

| 用語       | 意味                         | 覚え方                     |
|------------|------------------------------|----------------------------|
| イテラブル | `for` で使えるもの           | 繰り返せる                 |
| イテレータ | `next()` で値を1つずつ返すもの | 取り出しマシン             |

| 関数/メソッド | 内容                                 |
|----------------|--------------------------------------|
| `iter()`        | イテラブルからイテレータを作る        |
| `next()`        | イテレータから1個ずつ要素を取り出す    |
| `__iter__()`    | for文で最初に呼ばれる内部メソッド      |
| `__next__()`    | next()の中で実際に呼ばれる内部メソッド |

ここまで読んでいただきありがとうございます！  
私と同じように「イテラブルとイテレータってややこしい…」と思っていた方の助けになれば嬉しいです！