目次
1. yield キーワード
関数本体にyield キーワードが含まれている場合、関数を再度呼び出しても関数本体のコードは実行されず、取得される戻り値はジェネレータ オブジェクトです。
>>> def my_range(start,stop,step=1):
... print('start...')
... while start < stop:
... yield start
... start+=step
... print('end...')
...
>>> g=my_range(0,3)
>>> g
<generator object my_range at 0x104105678>
ジェネレーターには _iter_ および _next_ メソッドが組み込まれているため、ジェネレーター自体がセレクターです。
>>> g.__iter__
<method-wrapper '__iter__' of generator object at 0x1037d2af0>
>>> g.__next__
<method-wrapper '__next__' of generator object at 0x1037d2af0>
>>> next(g) # 触发函数执行直到遇到yield则停止,将yield后的值返回,并在当前位置挂起函数
start...
0
>>> next(g) # 再次调用next(g),函数从上次暂停的位置继续执行,直到重新遇到yield...
1
>>> next(g) # 周而复始...
2
>>> next(g) # 触发函数执行没有遇到yield则无值返回,即取值完毕抛出异常结束迭代
end...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
ジェネレーター オブジェクトはイテレーターに属しているため、次のように for ループ選択を使用できる必要があります。
yield キーワードを使用すると、カスタム セレクターを実装できます。Yield は値を返すために使用できますが、return とは異なり、関数は return に遭遇すると終了し、yield は関数の実行状態を保存し、関数を一時停止して複数の値を返すことができます
二、利回り式の適用
yield は関数内の式の形式を取ることができます
>>> def eater():
... print('Ready to eat')
... while True:
... food=yield
... print('get the food: %s, and start to eat' %food)
...
関数を取得できるジェネレーター オブジェクトは、次のように関数本体の送信値のままです。
>>> g=eater() # 得到生成器对象
>>> g
<generator object eater at 0x101b6e2b0>
>>> next(g) # 需要事先”初始化”一次,让函数挂起在food=yield,等待调用g.send()方法为其传值
Ready to eat
>>> g.send('包子')
get the food: 包子, and start to eat
>>> g.send('鸡腿')
get the food: 鸡腿, and start to eat
式の形式のyieldの場合、ジェネレーターオブジェクトを事前に一度初期化する必要があるため、関数は food=yield の位置で中断され、 g.send0 メソッドを呼び出して関数本体の値を渡すのを待ちます。 g.send(None) は next( g )と同等です。
次のように、すべての式フォームyieldに対応するジェネレーターの初期化を完了するデコレーターを書くことができます。
def init(func):
def wrapper(*args,**kwargs):
g=func(*args,**kwargs) #得到生成器(不会立刻有返回值)
next(g)
return g
return wrapper
@init
def eater():
print('Ready to eat')
while True:
food=yield
print('get the food: %s, and start to eat' %food)
次のように、式形式のyieldを使用して、複数の値を返すこともできます。つまり、変数名=収率値の形式です。
>>> def eater():
... print('Ready to eat')
... food_list=[]
... while True:
... food=yield food_list
... food_list.append(food)
...
>>> e=eater()
>>> next(e)
Ready to eat
[]
>>> e.send('蒸羊羔')
['蒸羊羔']
>>> e.send('蒸熊掌')
['蒸羊羔', '蒸熊掌']
>>> e.send('蒸鹿尾儿')
['蒸羊羔', '蒸熊掌', '蒸鹿尾儿']
三、三項式、リスト生成、ジェネレータ式
3.1 三項式
res = 条件成立时返回的值 if 条件 else 条件不成立时返回的值
3.2 リスト生成
もちろん、リストの他に辞書もあります. () はタプルを生成するのではなく、ジェネレータを生成することに注意してください!
egg_list=['鸡蛋%s' %i for i in range(10)]
3.3 ジェネレータ式
ジェネレーターオブジェクトを作成するには2つの方法があり、1つはyieldキーワードで関数を呼び出す方法、もう1つはジェネレーター式で、リスト生成と同じ文法形式で、口を()に置き換えるだけです。つまり:
>>> [x*x for x in range(3)]
[0, 1, 4]
>>> g=(x*x for x in range(3))
>>> g
<generator object <genexpr> at 0x101be0ba0>
リスト生成と比較して、ジェネレーター式の利点は当然、メモリを節約できることです (一度にメモリ内に生成される値は 1 つだけです)。
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g) #抛出异常StopIteration
大きなファイルのバイト数を読み取りたい場合は、ジェネレータ式に基づいて実行する必要があります
with open('db.txt','rb') as f:
nums=(len(line) for line in f)
total_size=sum(nums) # 依次执行next(nums),然后累加到一起得到结果=