LoginSignup
5
5

イテラブルやイテレータとは

Last updated at Posted at 2021-07-03

Pythonでfor文について調べていくと必ずでてくるのがイテレータ。
なんだかわかったようでわからない謎な解説ばかりです。
そんなわけでピストルで解説します(もっと謎)。

pistol.jpg

弾を詰めて、引き金を引くと一発ずつ発射し、すべてのたまを撃ち終わると終了という普通のピストルです。5発の弾が入るピストルなら5発打つまでは繰り返し、撃つことができます。

イテレーションとは繰り返すという意味です。辞書をひくと繰り返しとでてきます。
で、イテレーションとイテレータは微妙に違います。実はイテラブルという言葉もあって混乱しがちなのですが、まずは登場人物をあげてみます。

➀イテレーション
➁イテラブル
➂イテレータ

➀ イテレーション

一番攻略しやすいのはイテレーションです。
イテレーションとは先程述べたように「繰り返し」という意味になります。
たとえば 

for i in range(5):
    処理

と書けば処理を5回繰り返しますが、この繰返しのことをイテレーションといいます。

➁イテラブル

次に攻略しやすいのはイテラブルです、繰り返しの元を提供するものということで
ピストルの例えでいうと、リボルバーや弾倉とでも言ったらいいでしょうか

たとえば

a = [1, 2, 3, 4, 5]
for i in a:
    処理

と書いたときの

配列a

がイテラブルです。

➂ イテレータ

最後に真打ちのイテレータですが、こいつは装填済み発射寸前の銃本体みたいなイメージです。引き金が引かれるのを待つばかりといった感じです。(この文、コメントの指摘を受けて修正しました)

Pythonではイテラブルをiter()関数に突っ込んだ結果のオブジェクトがイテレータです。イテラブルが配列aなら iter(a)がイテレータになります。
たとえば

it = iter(a)

 とかくと itがイテレータになります。

引き金に相当するのがnext()関数で、
it.next()とすると弾丸が発射されるイメージです。

配列aの中の要素が1発ずつ発射されていきます。

実際にやってみましょう
Jupyter notebookで

a = [1,2,3,4,5]

と入力します。ここでクイズですが、aはなんだったでしょうか
答えはイテラブルですね。
その次のセルに

it = iter(a)

と入力します。ここでまたクイズです。itはなんだったでしょうか

答えはイテレータですね。

ここで print(next(it)) とすると
1 と表示
弾が1発、発射され、銃本体には4発残っています。

続けてprint(next(it))とすると
2 と表示
2発目の弾が発射され、銃本体には3発残っています。

続けてprint(next(it))とすると
3 と表示
3発目の弾が発射され、銃本体には2発残っています。

続けてprint(next(it))とすると
4 と表示
4発目の弾が発射され、銃本体には1発残っています。

続けてprint(next(it))とすると
5 と表示
5発目の弾が発射され、ここで弾切れになります。

続けてprint(next(it))とすると
StopIteration エラーになります

もう一度整理してみます。

イテレーション: 繰り返しのこと、ピストルのたとえだと、繰り返し撃てること
イテラブル :リストa、ピストルのたとえだと、弾倉
イテレータ :iter(a)、ピストルのたとえだと、銃本体

という関係になっています。以下は証拠のキャプチャ画像です。

##キャプチャ.jpg

まとめ

イテレータはなんのためにあるのか

→  順番に1つずつ処理するため

どうやってつくるのか

→  iter()関数

なにをつくるのか

→  オブジェクト(イテレータオブジェクト)

最後になってエラーがでたとき

→ try exceptで処理

サンプル

a=iter([1,2,3])  #aはイテレータオブジェクト

b1=next(a)    #1つずつ処理
print(b1)

b2=next(a)
print(b2)

b3=next(a)
print(b3)

try:
    b4=next(a)
    print(b4)
except StopIteration:  #ここで例外処理
    print("end")    

後日談 2024/01/26追加

その後、ふとある疑問が....

iter()は関数である。関数であるからには状態を持てないはず
状態を持てないとイテラブルから値を1つずつ取り出すなんてできないはず
状態が持てないと、どこまで取り出したか忘れちゃうので
あれれ、いったいどうなっているのか???

クラスかクロージャを使っているんだろうと予想ができたのでchatGPTに聞いてみました

    iter()はクラスですか、答えno
    iter()はクロージャを使っているのか No

うーむ謎は深まるばかり。。。。。

この謎がわかったのは

イテラブル自体がオブジェクトだということ思い出したときです。たとえばar=[1,2,3]とすると、こいつはオブジェクトなのでメソッドをもてます。もちろん状態も持てる!! と書こうとおもってchatGPTに聞いたらそれも間違いだと言われました。

正解は

たとえば、for文が実施される前にイテレータオブジェクトというものが新たに作られます。イテレータオブジェクトは現在位置などの情報(プロパティ)を持ったクラスです。つまりイテラブルとは別のオブジェクト。イテレータオブジェクトがあるおかげで、たとえば、ar.next()を実行するたび、内部のプロパティが変化して、ひとつずつ値が取り出せるというわけなのでした。

まとめ

iter(ar)はar.__iter__()を呼ぶ関数,イテレータオブジェクトを作り出す
next(ar)はar.__next__()を呼ぶ関数,位置をずらす

といったことをやっています。
浅い理解で書いてしまったので、あわてて記事の前半を読み返したのですが、とりあえず間違ったことは書いてなさそうなので一安心しました。が、なにかまちがっていたらつっこみのほう優しくお願いします。

5
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5