pythonの反復器とジェネレータ(一)--反復器


pythonを学ぶ資料では、反復器やジェネレータという名詞がよく見られます.しかし、いったい何が反復器なのか、何が生成器なのか.なぜこのようなタイプが現れたのか、彼らには何か便利なところがありますか?
反復とは?
簡単に言えばループ操作で、あるプロセスを何度も繰り返します.反復可能なオブジェクトはforループで反復できます.
反復可能オブジェクトとは?
一般的な反復オブジェクトには、シーケンス、辞書、ファイルなどがあります.また、他のオブジェクトもあります.反復可能なオブジェクトの特徴は、__が実装されていることです.iter__方法.例:
>>> alist=[1,2,3]
>>> lst=alist.__iter__()
>>> type(lst)
<type 'listiterator'>
>>> atuple=(1,2,3)
>>> tup=atuple.__iter__()
>>> type(tup)
<type 'tupleiterator'>
>>> afile=open(r"e:\test.txt",'r')
>>> fl=afile.__iter__()
>>> type(fl)
<type 'file'>
>>> astr='abc'
>>> string=astr.__iter__()

Traceback (most recent call last):
  File "<pyshell#62>", line 1, in <module>
    string=astr.__iter__()
AttributeError: 'str' object has no attribute '__iter__'
>>> iter(astr)
<iterator object at 0x0212BE70>
>>> string=iter(astr)
>>> anum=1
>>> iter(anum)

Traceback (most recent call last):
  File "<pyshell#66>", line 1, in <module>
    iter(anum)
TypeError: 'int' object is not iterable
>>> type(string)
<type 'iterator'>
>>> 

私たちは気づきました.iter__メソッドが返すオブジェクトは反復オブジェクトです.文字列astrには__がありませんiter__メソッドですが、組み込み関数iter()で呼び出すことができるので、反復可能なオブジェクトです.一方、デジタルanumではiter()は呼び出せないため、反復不可能なオブジェクトです.したがって、iter()を用いて、1つのオブジェクトが反復可能なオブジェクトであるか否かを判断することができる.
組み込み関数iter()とメソッド_iter__の関係:
>>> help(list.__iter__)
Help on wrapper_descriptor:

__iter__(...)
    x.__iter__() <==> iter(x)

>>> 

反復器とは?
反復器はnext()メソッドのあるオブジェクトです.
Python 3.0では反復規則が若干変更されており、反復オブジェクトは実装されるべきである_next__nextではなくメソッド.新しい組み込み関数nextは、この方法にアクセスするために使用できます.すなわち、next(it)は3.0以前のバージョンのitに等しい.next().
上の反復器にnext()があるかどうかを見てみましょう.
>>> lst.next()
1
>>> tup.next()
1
>>> fl.next()
'\xef\xbb\xbfHello world!
' >>> string.next() 'a'

どのように反復しますか?
バックグラウンドでは、for文がコンテナオブジェクトでiter()を呼び出す.この関数はnext()メソッドを定義した反復器オブジェクトを返し、コンテナ内で要素に1つずつアクセスします.後続の要素がない場合、next()はStopIteration異常を放出します.これはエラーが発生したことを意味するものではありません.外部呼び出し者に通知し、for文のループが終了し、反復が完了します.
次に、その動作原理の例を示します.
>>> s='abc'
>>> it=iter(s)
>>> it
<iterator object at 0x0228F9D0>
>>> it.next()
'a'
>>> it.next()
'b'
>>> it.next()
'c'
>>> it.next()

Traceback (most recent call last):
  File "<pyshell#33>", line 1, in <module>
    it.next()
StopIteration
>>> 

反復器のカスタマイズ方法
反復プロトコルのバックグラウンドメカニズムを理解すると、自分のクラスに反復動作を簡単に追加できます._を定義iter__()メソッドは、next()メソッドを持つオブジェクトを返します.このクラスがnext()を定義している場合、_iter__()self()を返すだけです.
>>> class Reversestr:
	'Iterator for looping over a swquence backwards'
	def __init__(self,data):
		self.data = data
		self.index = len(data)
	def __iter__(self):
		return self
	def next(self):
		if self.index == 0:
			raise StopIteration
		self.index = self.index - 1
		return self.data[self.index]

	
>>> for char in Reversestr('spam'):
	print char

	
m
a
p
s
>>> 

反復器の利点は何ですか?リストはできませんか?
反復可能な計算値の関数がある場合、使用時に指定した値のみを取得する必要があり、すべての値のリストを取得する必要はありません.この場合、数値が多い場合は、リストを使用するとメモリが多すぎます.もちろん、反復器を使うのはもっと簡単で優雅です.
リストを使用しない例を見てください.そのようなリストの長さは無限でなければなりません.
>>> class Fibs():
	def __init__(self):
		self.a=0
		self.b=1
	def next(self):
		self.a,self.b = self.b,self.a + self.b
		return self.a
	def __iter__(self):
		return self

	
>>> 

Fibsオブジェクトを作成するには、次の手順に従います.
>>> fibs = Fibs()

forループでこのオブジェクトを使用します.たとえば、フィボナッチ数列で500より大きい最小数を検索します.
>>> for f in fibs:
	if f > 500:
		print f
		break

	
610

breakが設定されているので、ループが停止します.そうしないと、ずっと続きます.
反復可能オブジェクトと反復可能オブジェクトの関係
組み込み関数iterは、listを例に、反復可能なオブジェクトから反復器を取得できます.
>>> a=[1,2,3]
>>> type(a)
<type 'list'>
>>> it=iter(a)
>>> type(it)
<type 'listiterator'>
>>> it.next()
1
>>> it.next()
2
>>> it.next()
3
>>> it.next()

Traceback (most recent call last):
  File "<pyshell#140>", line 1, in <module>
    it.next()
StopIteration
>>> 

注意:iter(a)とa._iter__()等価.
逆にlistコンストラクションメソッドを使用すると、反復器をリストに変換できます.
>>> a=[1,2,3]
>>> it=iter(a)
>>> list(it)
[1, 2, 3]
>>> 

まとめ:
反復可能オブジェクト:実装された__iter__メソッドのオブジェクト.
反復器:nextメソッドを実装したオブジェクト.
関係:_iter__メソッドは反復器を返します.
参考資料:
  • Pythonリファレンスマニュアル
  • Python基礎チュートリアル(第2版)