天天看點

python-生成器常見用法1 建立生成器–清單推導式2 擷取生成器的值–next3 建立生成器–函數+yield4 yield + return5 擷取生成器的值–send6 生成器應用總結

之前介紹過清單推導式,清單推導式缺點:

1、建立清單推導式時就給他配置設定了記憶體空間,當清單很大時,會占用大量記憶體空間

2、我們可能隻用到清單中前幾個元素,後續才能用到其他元素,造成記憶體白白占用不釋放

解決:

1、使用生成器(generator),不用建立完整的list,一邊循環一邊建立

今天我們就來介紹一下生成器

1 建立生成器–清單推導式

[] 是清單推導式,() 是生成器

# 清單推導式
list1 = [x for x in range(10)]
print(type(list1))

# 生成器
generator1 = (x for x in range(10))
print(type(generator1))
           

運作結果:

<class 'list'>
<class 'generator'>
           

2 擷取生成器的值–next

# 擷取生成器的值:隻有在擷取值的時候才會配置設定每個值的記憶體空間
# 方式1:__next__()
print(generator1.__next__())    # 0
print(generator1.__next__())    # 1
print(generator1.__next__())    # 2
# 方式2:next()
print(next(generator1))         # 3
print(next(generator1))         # 4
print(next(generator1))         # StopIteration:當生成器中的元素被取完時,報錯
           

3 建立生成器–函數+yield

首先看函數func1

def func1():
    n = 0
    while True:
        n += 1
           

func1是個死循環函數

用yield關鍵字

def func():
    n = 0
    while True:
        n += 1

        # yield功能 = return n + 暫停
        # 當此次next調用時,遇到yield,則将yield後的值作為函數傳回值傳回,暫停在這
        # 下次next調用時,從yield後繼續執行 --> print(f'n={n}') -> 再次進入到while循環
        # 再次遇到yield,return n + 暫停
        yield n
        print(f'n={n}')

g = func()              # 用debug模式檢視,g=func()時并未真正執行func函數,隻有在next時才進入func内部執行
print(type(g))          # <class 'generator'>

print(g.__next__())     
print('===========')
print(next(g))
           

加了yield關鍵字,func()則變成了一個生成器generator,則可用__next__()或next()對生成器取值

運作結果:

===========
<class 'generator'>
===========
start
1
===========
n=1
2
           

4 yield + return

def func(length):
    a = 0
    while a<length:
        yield a
        a += 1
    return '沒有更多資料了,循環結束'   # 當生成器的值被取完時,報錯資訊 StopIteration的内容就是return中的内容

g = func(2)
print(next(g))
print(next(g))      
print(next(g))      # StopIteration: 沒有更多資料了,循環結束
print(next(g))      # 不會被執行
           

5 擷取生成器的值–send

def func():
    i = 0
    while i < 5:
        tmp = yield i
        print(f'tmp={tmp}')
        i += 1

g = func()

print('===========')
print(next(g))
print('===========')
print(next(g))
           

運作結果:

===========
0
===========
tmp=None
1
           

可以通過send方法給yield傳值

def func():
    i = 0
    while i < 5:
        tmp = yield i
        print(f'tmp={tmp}')
        i += 1

g = func()

# 第一次必須要傳遞None
n0 = g.send(None)
print(f'send1: {n0}')     # 遇到yield暫停,并return i=0 給n0

print('=========')
# 第二次調用,從tmp = yield i處執行,send的值tmp1傳遞給tmp
# 往下執行 print(f'tmp={tmp}')  --> tmp=tmp1
# 往下執行 i+=1  --> i=1
# 往下執行再次進入while循環,遇到yield暫停,return i 給n1  --> n1=1
n1 = g.send('tmp1')
print(f'send2: {n1}')

print('=========')
n2 = g.send('tmp2')
print(f'send3: {n2}')
           

運作結果:

send1: 0
=========
tmp=tmp1
send2: 1
=========
tmp=tmp2
send3: 2
           

send的用途:需要生成元素,并且外界還可傳遞元素時

'''
next():在調用時生成器生成元素
send(value):調用時生成元素,還可以往生成器傳遞值
'''

def func():
    i = 0
    while i < 5:
        tmp = yield i
        for x in range(tmp):
            print(f'調用時傳遞值------>  x={x}')
        i += 1

g = func()

g.send(None)
print(f'生成器生成的元素---> {g.send(2)}')
           

6 生成器應用

生成器可用在攜程中,交替調用函數時

def task1(n):
    for i in range(n):
        print(f'吃第{i}顆糖')
        yield

def task2(n):
    for i in range (n):
        print (f'喝第{i}次水')
        yield

g1 = task1(2)
g2 = task2(2)

while True:
    try:
        g1.__next__()
        g2.__next__()
    except:
        break
           

運作結果:

吃第0顆糖
喝第0次水
吃第1顆糖
喝第1次水
           

總結

生成器生成方式:

1、清單推導式方式

g = (x for x in range(10))

2、函數+yield

def func():

yield

g = func()

生成器取值

1、next(generator) --> 每次調用都會産生新的元素,當元素調用完,報錯StopIteration

2、生成器内部方法

g.next()

g.send(value)

生成器應用:協程