calendarcodediamondfacebookfingerglobalgoogleplushatenahomepagetopplainpocketrssservicetwitterwordpresshome2searchfoldernext-arrowback-arrowfirst-arrowlast-arrow

Python : __iter__()はイテレータを返し、__next__()は次の要素を返す

Pythonにおけるイテレータとはなんだろう?イテレータオブジェクト(list、tuple、set など)は内部にイテレータを持ち、for 文で要素を反復的に処理する際に自動的に使われる。要は、コンテナに入っている要素一つ一つアクセスして返している。

エンジニア速報は Twitter の@commteで配信しています。

Sponsored Link

イテレータのポイント

  • __iter__()__next__()が実装されている
  • コンテナに入っている要素を一つ一つアクセスして返す
  • イテレータは使い終わると空になる

for i in X と書いたとき、for 文は X の iter() を呼び出し、その戻り値を利用する。この戻り値はイテレータと呼ばれる。in の後に指定されたオブジェクトには必ず iter()が適用される。

イテレータの中身

イテレータオブジェクトには、__iter__()__next__()が実装されている。

実際に、iter()のプロパティを見てみると確認できる。

iter()のプロパティ

a = iter([1, 2, 3, 4]) print(dir(a)) # [...'__iter__', '__next__',...]

list のプロパティ

a = [1, 2, 3, 4] print(dir(a)) # [...'__iter__'...] # '__next__' は含まれない

list には__next__()が含まれていない。つまりイテレータを生成できるが、次の要素にアクセスすることができないのである。

__iter__()__next__() の違い

__iter__()の戻り値は、そのイテレータ自身となる。反復機能を与える処理。

__next__()は、ループのたびに呼び出される。次の要素にアクセスする処理。

for や辞書以外のオブジェクトであっても__iter__()を実装すれば、イテレーションは可能である。例えばイテレータの機能を持つクラスを実装するには、__iter__()を実装すればよい。

イテラブルとイテレータの違い

イテラブルという言葉も頻出するので違いを書いておく。

__iter__()を実装しているオブジェクトは「イテラブル」と呼ばれ、__next__()を実装しているオブジェクトは「イテレータ」と呼ばれる。

list はイテラブルであり、イテレータではない。

イテラブル

  • __iter__()を実装
  • __iter__()の戻り値は任意のイテレータ

イテレータ

  • __iter__()__next__()を実装
  • __iter__()の戻り値は self

イテレータは必ずイテラブルだが、イテラブルはイテレータとは限らない。名前が似ているのでややこしい。

list と イテレータの違い

イテレータオブジェクトは次の要素を取得できるが、list には次の要素を取得する機能はない。

欲しいときに 1 個ずつ値を取得するには、値を 1 個だけ計算する関数があればよい。list を使って最初に全ての値を用意する必要はない。イテレータの代わりに list を使うのはメモリの無駄なのだ。

イテレータは、使い終わると要素が空になる

イテレータは使い終わると空になるが、list は要素が残る。

list → 全部残る list → イテレータ(next) → 空

iter() の作り方

実際にイテレータを作ってみる。

__iter__()は、イテレータオブジェクトを返す。print すると <list_iterator object at 0x7fae4ab4f2d0> と表示されている。list を使うと要素が表示された。

a = [1, 2, 3, 4] b = iter(a) print(b) list(b) # <list_iterator object at 0x7fae4ab4f2d0> # [1, 2, 3, 4]

iter()を使うと、イテラブルなオブジェクト(iter)からイテレータ(next)を取得できる。

a = iter([1, 2, 3, 4]) next(a) next(a) # 2

next() の使い方

next()を使い、イテレータオブジェクトから、順に要素を取り出すことができる。

a = [1, 2, 3] b = iter(a) next(b) next(b) next(b) # 3

__next__

__next__メソッドを呼び出すと、イテレータは次の値を返す。ループのたびに呼び出される。返す値がなくなると、例外である StopIteration を生成する。

組み込み関数 next()にイテレータを渡すと、そのイテレータの__next__()が呼び出され、next()の戻り値として受け取れる。つまり、next() を使ってイテレータオブジェクトすると__next__と同じになる。

ジェネレーター

ジェネレーター(yield 文を含む関数)は、next 関数で次の値を取り出せる。yield 文によって値が一つ生成されるたびに関数は停止し、再開を待つ。

以下のコードは、next が呼ばれるまで処理が中断されている例である。

def g(): yield 1 yield 2 yield 3 a = g() print(next(a)) print(next(a)) print(next(a)) # 1 # 2 # 3 # StopIteration → 値がなくなると例外

next()を__next__() に変えても同じ結果になる。

def g(): yield 1 yield 2 yield 3 a = g() print(a.__next__()) print(a.__next__()) print(a.__next__()) # 1 # 2 # 3

Python おすすめ本

スポンサード リンク

Comments

Leave a Comment

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください