python generators
12968 ワード
この文章はここから訳す
次の記事を振り返ってpythonでiteratorを作成することを議論します.iteratorを作成するには、有_を実装する必要があります.iter__()と_next__()メソッドのクラス、クラスは内部状態を追跡することができ、要素が戻ってこないときにStopIteration異常を引き起こす.
この過程は煩雑で直感に反する.Generatorはこの問題を解決することができる.
python generatorはiteratorを簡単に作成する方法です.前に述べた煩雑な手順はgeneratorによって自動的に完成することができる.
簡単に言えば、generatorは反復器のオブジェクトを返すことができる関数である.
python generatorを作成するにはどうすればいいですか?
関数を作成するように簡単ですが、return宣言ではなくyield宣言を使用します.
1つの関数が少なくとも1つのyield宣言を含む場合(もちろん他のyieldまたはreturnを含むこともできる)、それはgeneratorである.
yieldとreturnは関数にいくつかのものを返します.違いは、return宣言は完全に関数を終了し、yield宣言は関数を一時停止し、そのすべての状態を保存し、その後呼び出された後も実行し続けることです.
generator関数と一般関数の違い generator関数は、1つ以上のyield宣言 を含む. generator関数が呼び出されるとiteratorオブジェクトが返されますが、関数はすぐに の実行を開始しません. __iter__()と_next__()メソッドは自動的に実装されるので、next()関数を使用して、返されるこのiteratorオブジェクトを 反復することができる. generatorがyield文に実行するとgenerator関数は一時停止し、プログラム制御フローは呼び出し元 に移行する. generatorに対する連続呼び出しの間にgeneratorのローカル変数とステータスが 保存される.最終的にgenerator関数は終了し、再びgeneratorを呼び出すとStopIteration異常 が発生する.
次の例では、上記のすべてのポイントを説明します.myという名前があります.gen()の関数で、yield宣言があります.
上記の手順を繰り返すには、a=my_のようなものが必要です.gen()は、別のgeneratorオブジェクトを作成し、nextメソッドを使用して反復します.
注意:generatorオブジェクトに対してforループを直接使用できます.
これは、forループがiteratorオブジェクトを受信し、next()関数を使用して反復し、StopIteration異常が発生した場合に自動的に停止するためです.pythonがforループをどのように実現しているかを確認するには、ここをクリックします.
循環python generator
上の例は実際の応用意義がなく,我々はただ背後の原理を探究するためである.
通常、generatorはサイクルと結合して実現され、このサイクルは終了条件を有する.
reverseの文字列の例を見てみましょう
generatorはstringに適用できるほか、list、tupleなどの他のタイプのiteratorにも適用できる.
python generator式
generator式を使用すると、簡単なgeneratorを簡単に作成できます.
Lambda関数が匿名関数を作成できるように、generator関数は匿名generator関数を作成します.
generator式の構文はpythonのlist comprehensionに似ていますが、角カッコが丸カッコに置き換えられているだけです.
list comprehensionとgenerator式の主な違いは、前者はすべてのlistを生成し、後者は毎回1つしか生成しないことです.
怠け者で、リクエストを受けたときだけ出力が発生します.したがって、generator式はlist comprehensionよりもメモリを節約します.
pythonではなぜgeneratorを使うのですか?次のいくつかの理由でgeneratorが魅力的な選択になりました
1.実現しやすい
iteratorクラスに比べてgeneratorの実現は明確で簡潔である.次はiteratorで2を実現する指数関数です
2.メモリの節約
1つの関数が1つのシーケンス(sequence)を返すと、メモリにこのシーケンスを構築して返します.このシーケンスに多くのデータが含まれていれば、過ぎたるは及ばざるがごとし.
シーケンスがgenerator方式で実現されている場合、メモリは友好的です.彼は毎回1つのitemしか生成しないからです.
3.無限のstreamを表す
generatorは無限のデータストリームを表す素晴らしいツールです.無限データストリームはメモリに保存できません.generatorはitemを生成するたびに無限データストリームを表すことができます.
次のコードはすべての奇数を生成することができます
4.generatorパイプライン(pipeline)
generatorは、一連の操作に対して流水線操作を実行することができる.
ファーストフードチェーンのログがあるとします.ログの4列目は1時間に販売されるピザの数で、5年近くのこのデータを合計したいと思っています.
すべてのデータが文字であると仮定し、使用できないデータは「N/A」で表され、generatorを使用して実現できます.
次の記事を振り返ってpythonでiteratorを作成することを議論します.iteratorを作成するには、有_を実装する必要があります.iter__()と_next__()メソッドのクラス、クラスは内部状態を追跡することができ、要素が戻ってこないときにStopIteration異常を引き起こす.
この過程は煩雑で直感に反する.Generatorはこの問題を解決することができる.
python generatorはiteratorを簡単に作成する方法です.前に述べた煩雑な手順はgeneratorによって自動的に完成することができる.
簡単に言えば、generatorは反復器のオブジェクトを返すことができる関数である.
python generatorを作成するにはどうすればいいですか?
関数を作成するように簡単ですが、return宣言ではなくyield宣言を使用します.
1つの関数が少なくとも1つのyield宣言を含む場合(もちろん他のyieldまたはreturnを含むこともできる)、それはgeneratorである.
yieldとreturnは関数にいくつかのものを返します.違いは、return宣言は完全に関数を終了し、yield宣言は関数を一時停止し、そのすべての状態を保存し、その後呼び出された後も実行し続けることです.
generator関数と一般関数の違い
次の例では、上記のすべてのポイントを説明します.myという名前があります.gen()の関数で、yield宣言があります.
# A simple generator function
def my_gen():
n = 1
print('This is printed first')
# Generator function contains yield statements
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
インタラクションでインタラクションした結果は、次のとおりです.>>> # It returns an object but does not start execution immediately.
>>> a = my_gen()
>>> # We can iterate through the items using next().
>>> next(a)
This is printed first
1
>>> # Once the function yields, the function is paused and the control is transferred to the caller.
>>> # Local variables and theirs states are remembered between successive calls.
>>> next(a)
This is printed second
2
>>> next(a)
This is printed at last
3
>>> # Finally, when the function terminates, StopIteration is raised automatically on further calls.
>>> next(a)
Traceback (most recent call last):
...
StopIteration
>>> next(a)
Traceback (most recent call last):
...
StopIteration
興味深いことに、この例では変数nが呼び出されるたびに記憶される.一般的な関数とは異なり、関数yield以降のローカル変数は破棄されず、generatorオブジェクトはこのように反復するしかありません.上記の手順を繰り返すには、a=my_のようなものが必要です.gen()は、別のgeneratorオブジェクトを作成し、nextメソッドを使用して反復します.
注意:generatorオブジェクトに対してforループを直接使用できます.
これは、forループがiteratorオブジェクトを受信し、next()関数を使用して反復し、StopIteration異常が発生した場合に自動的に停止するためです.pythonがforループをどのように実現しているかを確認するには、ここをクリックします.
# A simple generator function
def my_gen():
n = 1
print('This is printed first')
# Generator function contains yield statements
yield n
n += 1
print('This is printed second')
yield n
n += 1
print('This is printed at last')
yield n
# Using for loop
# Output:
# This is printed first
# 1
# This is printed second
# 2
# This is printed at last
# 3
for item in my_gen():
print(item)
循環python generator
上の例は実際の応用意義がなく,我々はただ背後の原理を探究するためである.
通常、generatorはサイクルと結合して実現され、このサイクルは終了条件を有する.
reverseの文字列の例を見てみましょう
def rev_str(my_str):
length = len(my_str)
for i in range(length - 1,-1,-1):
yield my_str[i]
# For loop to reverse the string
# Output:
# o
# l
# l
# e
# h
for char in rev_str("hello"):
print(char)
forループでrange()関数を使用して、逆順序のindexを取得します.generatorはstringに適用できるほか、list、tupleなどの他のタイプのiteratorにも適用できる.
python generator式
generator式を使用すると、簡単なgeneratorを簡単に作成できます.
Lambda関数が匿名関数を作成できるように、generator関数は匿名generator関数を作成します.
generator式の構文はpythonのlist comprehensionに似ていますが、角カッコが丸カッコに置き換えられているだけです.
list comprehensionとgenerator式の主な違いは、前者はすべてのlistを生成し、後者は毎回1つしか生成しないことです.
怠け者で、リクエストを受けたときだけ出力が発生します.したがって、generator式はlist comprehensionよりもメモリを節約します.
# Initialize the list
my_list = [1, 3, 6, 10]
# square each term using list comprehension
# Output: [1, 9, 36, 100]
[x**2 for x in my_list]
# same thing can be done using generator expression
# Output: at 0x0000000002EBDAF8>
(x**2 for x in my_list)
の上記の例では、generator式はすぐに必要な結果を生成するのではなく、itemを生成する必要があるときにgeneratorオブジェクトを返します.# Intialize the list
my_list = [1, 3, 6, 10]
a = (x**2 for x in my_list)
# Output: 1
print(next(a))
# Output: 9
print(next(a))
# Output: 36
print(next(a))
# Output: 100
print(next(a))
# Output: StopIteration
next(a)
generator式は、関数の内部で使用できます.このように使用すると、カッコを捨てることができます.>>> sum(x**2 for x in my_list)
146
>>> max(x**2 for x in my_list)
100
pythonではなぜgeneratorを使うのですか?次のいくつかの理由でgeneratorが魅力的な選択になりました
1.実現しやすい
iteratorクラスに比べてgeneratorの実現は明確で簡潔である.次はiteratorで2を実現する指数関数です
class PowTwo:
def __init__(self, max = 0):
self.max = max
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n > self.max:
raise StopIteration
result = 2 ** self.n
self.n += 1
return result
generatorこのように実現def PowTwoGen(max = 0):
n = 0
while n < max:
yield 2 ** n
n += 1
は、generatorが実装の詳細を自動的に追跡するため、より明確で簡潔である.2.メモリの節約
1つの関数が1つのシーケンス(sequence)を返すと、メモリにこのシーケンスを構築して返します.このシーケンスに多くのデータが含まれていれば、過ぎたるは及ばざるがごとし.
シーケンスがgenerator方式で実現されている場合、メモリは友好的です.彼は毎回1つのitemしか生成しないからです.
3.無限のstreamを表す
generatorは無限のデータストリームを表す素晴らしいツールです.無限データストリームはメモリに保存できません.generatorはitemを生成するたびに無限データストリームを表すことができます.
次のコードはすべての奇数を生成することができます
def all_even():
n = 0
while True:
yield n
n += 2
4.generatorパイプライン(pipeline)
generatorは、一連の操作に対して流水線操作を実行することができる.
ファーストフードチェーンのログがあるとします.ログの4列目は1時間に販売されるピザの数で、5年近くのこのデータを合計したいと思っています.
すべてのデータが文字であると仮定し、使用できないデータは「N/A」で表され、generatorを使用して実現できます.
with open('sells.log') as file:
pizza_col = (line[3] for line in file)
per_hour = (int(x) for x in pizza_col if x != 'N/A')
print("Total pizzas sold = ",sum(per_hour))
この流水線は効率的で読みやすく、かっこいいように見えます!:)