私は本からPythonを学んでおり、この例に出くわしました:
M = [[1,2,3],
[4,5,6],
[7,8,9]]
G = (sum(row) for row in M) # create a generator of row sums
next(G) # Run the iteration protocol
私は絶対的な初心者であり、著者は例やnext()関数の説明を提供していないため、コードが何をしているのか理解できません。
式_(sum(row) for row in M)
_は、generatorと呼ばれるものを作成します。このジェネレーターは、M
の行ごとに式(sum(row)
)を1回評価します。ただし、ジェネレーターはまだ何もしていません。セットアップしただけです。
ステートメントnext(G)
は実際にはrunsM
のジェネレーターです。したがって、next(G)
を1回実行すると、最初の行の合計が得られます。もう一度実行すると、2番目の行の合計が取得されます。
_>>> M = [[1,2,3],
... [4,5,6],
... [7,8,9]]
>>>
>>> G = (sum(row) for row in M) # create a generator of row sums
>>> next(G) # Run the iteration protocol
6
>>> next(G)
15
>>> next(G)
24
_
ここまで来たら、一般的なfor-inステートメントがどのように機能するかをすでに知っているはずです。
次のステートメント:
for row in M: print row
mは、それぞれ3つの項目で構成される3行のシーケンス(サブシーケンス)として認識され、Mを反復処理して、行列の各行を出力します。
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
あなたはそれを知っていた、よく...
For-inループの構文糖衣のように、ジェネレーターを見ることができます。 sum()呼び出しを忘れて、IDLEに次のように入力します。
G = (row for row in M)
print G
for a in G: print a
ジェネレータがシーケンスとしてだけでなく、テキストとして直接表現されることはありません。ただし、ジェネレーターをシーケンスのように反復処理できます。
いくつかの大きな違いを見つけることができますが、基本は、ジェネレーターを使用して、シーケンス内の各項目の値だけでなく、式の結果を返すことができるということです。チュートリアルの例では、式はsum(row)です。
以下を試して、何が起こるか見てください:
G = ("("+str(row[2])+";"+str(row[1])+";"+str(row[0])+")" for row in M)
G.next()
G.next()
G.next()
このコードがどのように機能するかを理解するには、以下を理解する必要があります。
1)反復可能なオブジェクト?
2)イテレーター?
3)反復プロトコル
4)発電機?
5)ジェネレーターはどのように機能しますか?
これらのそれぞれを垣間見てみましょう。
Iterable:iterableは、Pythonのオブジェクトで、iterまたはgetitemメソッドが定義され、イテレータまたはインデックスを取ることができます。基本的にループを実行できるオブジェクト。
>>> for i in [1,2,3]:
print(i)
1 2 3
ここには、反復可能なオブジェクトとしてリストがあり、そのアイテムはインデックスを使用してインデックス付けおよび取得できます。
>>> for i in {x:1,y:2}:
print(x)
x y
ここに反復可能なオブジェクトとして辞書があり、キーをループします。
イテレータ:イテレータは、Python next(Python2)またはnextメソッドが定義されている任意のオブジェクトです。これがイテレータです。 。
反復プロトコル:組み込み関数iterは反復可能なオブジェクトを受け取り、反復子を返します。
>>> x = iter([1, 2, 3])
>>> x
<listiterator object at 0x1004ca850>
>>> x.next()
1
>>> x.next()
2
>>> x.next()
3
>>> x.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Generator:Generatorsはイテレータですが、反復できるのは1回だけです。すべての値をメモリに保存するのではなく、その場で値を生成するためです。
例えば:
def yrange(n):
i = 0
while i < n:
yield i
i += 1
Yieldステートメントが実行されるたびに、関数は新しい値を生成します。
>>> y = yrange(3)
>>> y
<generator object yrange at 0x401f30>
>>> y.next()
0
>>> y.next()
1
>>> y.next()
2
>>> y.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
したがって、ジェネレータはイテレータでもあります。
注:next()が呼び出されるたびに、中断したところから再開します(すべてのデータ値と最後に実行されたステートメントを記憶します)。もう1つの重要な機能は、呼び出し間でローカル変数と実行状態が自動的に保存されることです。
例でこれを理解しましょう。
>>> def foo():
print "begin"
for i in range(3):
print "before yield", i
yield i
print "after yield", i
print "end"
>>> f = foo()
>>> f.next()
begin
before yield 0
0
>>> f.next()
after yield 0
before yield 1
1
>>> f.next()
after yield 1
before yield 2
2
>>> f.next()
after yield 2
end
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
それでは、問題に取り掛かりましょう。
M = [[1,2,3], #M is iterable object
[4,5,6],
[7,8,9]]
G = (sum(row) for row in M) # creates a generator of row sums
next(G) # Run the iteration protocol