国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python生成器定義與簡單用法實(shí)例分析

2020-01-04 15:17:09
字體:
供稿:網(wǎng)友

本文實(shí)例講述了Python生成器定義與簡單用法。分享給大家供大家參考,具體如下:

一、什么是生成器

在Python中,由于受到內(nèi)存的限制,列表容量肯定是有限的。例如我們創(chuàng)建一個(gè)包含一億個(gè)元素的列表,Python首先會(huì)在內(nèi)存中開辟足夠的空間來存儲(chǔ)這個(gè)包含一億個(gè)元素的列表,然后才允許用戶去使用這個(gè)列表,這就可能會(huì)導(dǎo)致以下問題:

  1、內(nèi)存中沒有足夠的內(nèi)存空間開存儲(chǔ)這個(gè)列表,從而導(dǎo)致列表無法創(chuàng)建

  2、即使列表成功創(chuàng)建,然而仍會(huì)消耗很長的時(shí)間,導(dǎo)致程序效率低下

  3、若用戶只想訪問列表前面的幾個(gè)元素,則后面列表絕大多數(shù)元素占用的空間就都白白浪費(fèi)了

為了有效解決以上的問題,Python中引入了一種“一邊循環(huán),一邊計(jì)算”的新機(jī)制,即當(dāng)用戶需要使用某個(gè)對象時(shí),Python才根據(jù)事先設(shè)計(jì)好的規(guī)則開辟內(nèi)存空間創(chuàng)建這個(gè)對象供用戶使用,而不是像列表一樣事先將所有的對象都創(chuàng)建完畢之后再提供給用戶使用。這種機(jī)制在Python中成為生成器(generator)。

二、生成器的創(chuàng)建

A、生成器推到式

與列表推到式類似,只不過生成器推導(dǎo)式使用()而非[],并且最終返回的是生成器而非列表

g=((i+2)**2 for i in range(2,30)) #g是一個(gè)生成器print(g) #g為空,里面包含任何元素

運(yùn)行結(jié)果:

<generator object <genexpr> at 0x0000000002263150>

B、yield關(guān)鍵字

在一個(gè)函數(shù)定義中包含yield關(guān)鍵字,則這個(gè)函數(shù)就不再是一個(gè)普通的函數(shù),而是一個(gè)生成器(generator)

[說明]:yield指令可以暫停一個(gè)函數(shù)并返回其中間結(jié)果,使用該指令的函數(shù)將保存執(zhí)行環(huán)境,并在必要時(shí)恢復(fù)

def fib(max):  n,a,b=0,0,1  while n<max:    #print(b)    yield b    a,b=b,a+b    n+=1  return 'done'f=fib(6)print(f)

運(yùn)行結(jié)果:

<generator object fib at 0x0000000002553150>

[注]:普通函數(shù)和變成生成器的函數(shù)的不同:

普通函數(shù)是順序執(zhí)行的,遇到return或是最后一行函數(shù)語句就返回。而變成生成器的函數(shù)在每次調(diào)用__next__()方法時(shí)執(zhí)行,遇到y(tǒng)ield語句返回,再次執(zhí)行時(shí)從上次返回的yield語句處繼續(xù)執(zhí)行

f=fib(6)print(f)print(f.__next__())print(f.__next__())print('暫停一下')print(f.__next__())print(f.__next__())

運(yùn)行結(jié)果:

<generator object fib at 0x00000000025631A8>
1
1
暫停一下
2
3

三、生成器方法(參考:伯樂在線)

1.close()方法:手動(dòng)關(guān)閉生成器函數(shù),后面的調(diào)用會(huì)直接返回StopIteration異常

def func():  yield 1  yield 2  yield 3g=func()g.__next__()g.close() #手動(dòng)關(guān)閉生成器g.__next__() #關(guān)閉后,yield 2和yield 3語句將不再起作用

運(yùn)行結(jié)果:

Traceback (most recent call last):
  File "E:/py3Demo/Hello/generatorDemo.py", line 9, in <module>
    g.__next__() #關(guān)閉后,yield 2和yield 3語句將不再起作用
StopIteration

2.__next__()方法:返回生成器的下一次調(diào)用

def func():  n=1  for i in range(3):    yield n    n+=1c=func()a1=c.__next__()a2=c.__next__()a3=c.__next__()

[流程解釋]:

對于普通的生成器,第一個(gè)__next__()方法的調(diào)用相當(dāng)于啟動(dòng)生成器,此時(shí)會(huì)從生成器函數(shù)的第一行開始執(zhí)行,直到第一次執(zhí)行完yield語句(第四行)后,跳出生成器函數(shù)。

當(dāng)調(diào)用第二個(gè)__next__()方法后,會(huì)重新進(jìn)入生成器函數(shù),并從yield語句的下一條語句(第五行)開始執(zhí)行,直到重新運(yùn)行到y(tǒng)ield語句,執(zhí)行后再次跳出生成器函數(shù)。

后面的__next__()方法調(diào)用以此類推

3.send()方法:接受外部傳入的一個(gè)變量,并根據(jù)變量內(nèi)容計(jì)算結(jié)果返回到生成器函數(shù)中

[注]:

(1)send()方法和__next__()方法相似,區(qū)別在于send()方法可以傳遞給yield表達(dá)式值,而__next__()方法不能傳遞特定的值,只能傳遞None給yield表達(dá)式,因此可以將generator.__next__()理解為generator.send(None)

(2)第一次調(diào)用生成器函數(shù)時(shí),必須使用__next__()語句或是send(None),不能使用send發(fā)送一個(gè)非None的值給生成器函數(shù),否則會(huì)出錯(cuò),因?yàn)闆]有yield語句來接收這個(gè)值

def gen():  value=0  while True:    receive=yield value    if receive=='end':      break    value='Got:%s' %receiveg=gen()print(g.__next__()) #或是print(g.send(None)),從而啟動(dòng)生成器print(g.send('aaa'))print(g.send(3))print(g.send('end'))

運(yùn)行結(jié)果:

0
Got:aaa
Got:3
Traceback (most recent call last):
  File "E:/py3Demo/Hello/generatorDemo.py", line 13, in <module>
    print(g.send('end'))
StopIteration

[流程解釋]:

a.通過g.send(None)或g.__next__()啟動(dòng)生成器函數(shù),并執(zhí)行到第一個(gè)yield語句結(jié)束的位置并將函數(shù)掛起。此時(shí)執(zhí)行完了yield語句,但是沒有給receive賦值,因此yield value會(huì)輸出value的初始值0

b.g.send('aaa')先將字符串‘aaa'傳入到生成器函數(shù)中并賦值給receive,然后從yield語句的下一句重新開始執(zhí)行函數(shù)(第五句),計(jì)算出value的值后返回到while頭部開始新一輪的循環(huán),執(zhí)行到y(tǒng)ield value語句時(shí)停止,此時(shí)yield value會(huì)輸出‘Got:aaa',然后掛起

c.g.send(3)重復(fù)步驟b,最后輸出結(jié)果為‘Got:3'

d.g.send('end')會(huì)使程序執(zhí)行break然后跳出循環(huán),從而函數(shù)執(zhí)行完畢,得到StopIteration異常

4.throw()方法:向生成器發(fā)送一個(gè)異常。

def gen():  while True:    try:      yield 'normal value' #返回中間結(jié)果,此處的yield和return的功能相似      yield 'normal value2'      print('I am here')    except ValueError:      print('We got ValueError')    except Exception:      print('Other errors')      breakg=gen()print(g.__next__())print(g.throw(ValueError))print(g.__next__())print(g.throw(TypeError))

運(yùn)行結(jié)果:

Traceback (most recent call last):
  File "E:/py3Demo/Hello/generatorDemo.py", line 17, in <module>
    print(g.throw(TypeError))
StopIteration
normal value
We got ValueError
normal value
normal value2
Other errors

[解釋]:

a.print(g.__next__())會(huì)輸出normal value,并停在yield 'normal value2'之前

b.由于執(zhí)行了g.throw(ValueError),所以回跳過后續(xù)的try語句,即yield ‘normal value2'不會(huì)執(zhí)行,然后進(jìn)入到except語句,打印出‘We got ValueError'。之后再次進(jìn)入到while語句部分,消耗一個(gè)yield,輸出normal value

c.print(g.__next__())會(huì)執(zhí)行yield ‘normal value2'語句,并停留在執(zhí)行完該語句后的位置

d.g.throw(TypeError)會(huì)跳出try語句,因此print('I am here')不會(huì)被執(zhí)行,然后打印‘Other errors',并執(zhí)行break語句跳出while循環(huán),然后到達(dá)程序結(jié)尾,打印StopIteration異常的信息

四、生成器的運(yùn)用

import timedef consumer(name):  print('%s準(zhǔn)備吃包子啦!' %name)  while True:    baozi=yield #接收send傳的值,并將值賦值給變量baozi    print('包子[%s]來了,被[%s]吃了!' %(baozi,name))def producer(name):  c1=consumer('A') #把函數(shù)變成一個(gè)生成器  c2=consumer('B')  c1.__next__()#調(diào)用這個(gè)方法會(huì)走到y(tǒng)ield處暫時(shí)返回  c2.__next__()  print('開始準(zhǔn)備做包子啦!')  for i in range(10):    time.sleep(1)    print('做了一個(gè)包子,分成兩半')    c1.send(i)    c2.send(i)producer('Tomwenxing')

運(yùn)行結(jié)果:

A準(zhǔn)備吃包子啦!
B準(zhǔn)備吃包子啦!
開始準(zhǔn)備做包子啦!
做了一個(gè)包子,分成兩半
包子[0]來了,被[A]吃了!
包子[0]來了,被[B]吃了!
做了一個(gè)包子,分成兩半
包子[1]來了,被[A]吃了!
包子[1]來了,被[B]吃了!
做了一個(gè)包子,分成兩半
包子[2]來了,被[A]吃了!
包子[2]來了,被[B]吃了!
做了一個(gè)包子,分成兩半
包子[3]來了,被[A]吃了!
包子[3]來了,被[B]吃了!
做了一個(gè)包子,分成兩半
包子[4]來了,被[A]吃了!
包子[4]來了,被[B]吃了!
做了一個(gè)包子,分成兩半
包子[5]來了,被[A]吃了!
包子[5]來了,被[B]吃了!
做了一個(gè)包子,分成兩半
包子[6]來了,被[A]吃了!
包子[6]來了,被[B]吃了!
做了一個(gè)包子,分成兩半
包子[7]來了,被[A]吃了!
包子[7]來了,被[B]吃了!
做了一個(gè)包子,分成兩半
包子[8]來了,被[A]吃了!
包子[8]來了,被[B]吃了!
做了一個(gè)包子,分成兩半
包子[9]來了,被[A]吃了!
包子[9]來了,被[B]吃了!

 

希望本文所述對大家Python程序設(shè)計(jì)有所幫助。


注:相關(guān)教程知識閱讀請移步到python教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 修武县| 武川县| 大兴区| 榆林市| 滨海县| 黄浦区| 观塘区| 呼伦贝尔市| 沙湾县| 花垣县| 衡水市| 伊吾县| 乐东| 太谷县| 山丹县| 南阳市| 板桥市| 霍山县| 沂水县| 五台县| 合阳县| 湛江市| 鄂州市| 永宁县| 永城市| 柞水县| 金坛市| 广昌县| 平凉市| 永德县| 水城县| 盐山县| 塔城市| 池州市| 桦甸市| 武山县| 永康市| 蓬溪县| 上杭县| 麻城市| 沾益县|