python3 生成器
要說生成器,就必須首先要知道列表的概念;
我們創建一個如下的列表:
ls = [1,2,3,4,5,6,7,8,9]
那么就開辟了一個門牌號為ls的內存區,然后真的把1,2,3,4,5,6,7,8,9這幾個數字放到了內存中;
如果我們在for循環中要根據i的值來獲取一個值的話,我們可以把數據放在上面的ls中,然后通過ls[i]來獲取;這樣的
方式存在巨大的缺點,就是要事先準備好ls中的所有數值;如果很多的話會造成響應慢,內存溢出等問題;
所以就有有了生成器的概念,生成器會指定一個公式,然后每次循環都根據公式計算出當前的值,不用事先生成
所有的值。
一、最簡單的生成器
# -*- coding:utf-8 -*- # Author: Evan Mi# 這是一個最基本的生成器,對應的公式是i*2,i從0到9 # 這樣我們就可以通過迭代的方式來訪問生成的每一個值了 # 它的缺點就是,只能逐一迭代,不能隨意指定i,也不能往前迭代 my_gen_01 = (i*2 for i in range(10)) """ 可以看到my_gen是一個generator對象 """ print(my_gen_01) # <generator object <genexpr> at 0x00000000024FCBA0> # generator對象是一個迭代器對象,所以直接通過next()方法來迭代 while True:try:print(next(my_gen_01)) # 迭代(根據公式計算)except StopIteration as e: # 迭代到沒有元素后會拋出StopIterationprint(e.value)break """ 運行結果: 0 2 4 6 8 10 12 14 16 18 None """ # 用for循環迭代,不會有異常拋出 # 需要新建一個,因為上一個已經被迭代完了(生成器是一次性用品) my_gen_02 = (i*2 for i in range(10))for val in my_gen_02:print(val) """ 運行結果: 0 2 4 6 8 10 12 14 16 18 """二、用函數來實現復雜的生成器
# -*- coding:utf-8 -*- # Author: Evan Mi# 引用別人的斐波那契數列生成函數 """函數運行到yield的時候,就會暫停,并將yield關鍵字之后的值傳到函數外,函數暫停在這里,直到等到下一次迭代""" def fib(max_num):n, a, b = 0, 0, 1while n < max_num:yield ba, b = b, a+bn += 1# 定義了一個生成器,這個生成器每次迭代得到的值就是yield帶出來的值fb = fib(10)# 用for循環迭代 for val in fb:print(val) """ 運行結果: 1 1 2 3 5 8 13 21 34 55 """ # 用next迭代 fb1 = fib(10) while True:try:print(next(fb1))except StopIteration as e:print(e.value)break """ 運行結果: 1 1 2 3 5 8 13 21 34 55 None """可以看到,在使用for循環迭代的時候,并不需要自己去處理迭代停止的異常;而用next自己處理就需要;而且
我們每次的e.value都是none;現在給函數加上返回值,如下:
def fib(max_num):n, a, b = 0, 0, 1while n < max_num:yield ba, b = b, a+bn += 1return 'done'對這樣的函數,我們用next調用;
# 用next迭代 fb1 = fib(10) while True:try:print(next(fb1))except StopIteration as e:print(e.value)break """ 運行結果: 1 1 2 3 5 8 13 21 34 55 done """可以看到e.value變成了done;所以一個函數如果作為了生成器,那么return的值就是迭代停止時的異常信息;
yield能帶出函數中的值,那么yield就是函數內部與外界的媒介,那么自然也能從外部代值回來:
修改函數如下:
def fib(max_num):n, a, b = 0, 0, 1while n < max_num:xxx = yield b # 后面的b在運行到yield時被帶出去,前面的xx在激活yield時被帶進來print(xxx)a, b = b, a+bn += 1return 'done'執行如下的測試:
gx = fib(10) # 一開是只能調用next,因為這時只是創建了一個生成器,還沒有yield變量 print('out;', next(gx)) # 把233給yield,同時往下運行到下一次循環到yield處,并帶回yield的值 print('out;', gx.send(233)) print('out;', gx.send(333)) print('out;', gx.send(433)) # 循環到下一次的yield,并帶回yield的值(其實就是把None給了yield) print('out;', next(gx))運行結果如下:
out; 1? 第一次只能從yield帶出值
233? ? 通過yield傳入了233,在函數內部打印
out; 1? ? 帶出1
333? ? 傳入333
out; 2 帶出2
433 傳入433
out; 3 帶出3
None 傳入None
out; 5 帶出5
總結
以上是生活随笔為你收集整理的python3 生成器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用键盘控制音量的软件
- 下一篇: websocket python爬虫_p