一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - Python生成器定義與簡單用法實例分析

Python生成器定義與簡單用法實例分析

2021-02-08 00:31Tom文星 Python

這篇文章主要介紹了Python生成器定義與簡單用法,結合實例形式較為詳細的分析了Python生成器的概念、原理、使用方法及相關操作注意事項,需要的朋友可以參考下

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

一、什么是生成器

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

  1、內存中沒有足夠的內存空間開存儲這個列表,從而導致列表無法創建

  2、即使列表成功創建,然而仍會消耗很長的時間,導致程序效率低下

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

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

二、生成器的創建

A、生成器推到式

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

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

運行結果:

<generator object <genexpr> at 0x0000000002263150>

B、yield關鍵字

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

[說明]:yield指令可以暫停一個函數并返回其中間結果,使用該指令的函數將保存執行環境,并在必要時恢復

?
1
2
3
4
5
6
7
8
9
10
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)

運行結果:

<generator object fib at 0x0000000002553150>

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

普通函數是順序執行的,遇到return或是最后一行函數語句就返回。而變成生成器的函數在每次調用__next__()方法時執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行

?
1
2
3
4
5
6
7
f=fib(6)
print(f)
print(f.__next__())
print(f.__next__())
print('暫停一下')
print(f.__next__())
print(f.__next__())

運行結果:

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

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

1.close()方法:手動關閉生成器函數,后面的調用會直接返回StopIteration異常

?
1
2
3
4
5
6
7
8
def func():
  yield 1
  yield 2
  yield 3
g=func()
g.__next__()
g.close() #手動關閉生成器
g.__next__() #關閉后,yield 2和yield 3語句將不再起作用

運行結果:

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

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

?
1
2
3
4
5
6
7
8
9
def func():
  n=1
  for i in range(3):
    yield n
    n+=1
c=func()
a1=c.__next__()
a2=c.__next__()
a3=c.__next__()

[流程解釋]:

對于普通的生成器,第一個__next__()方法的調用相當于啟動生成器,此時會從生成器函數的第一行開始執行,直到第一次執行完yield語句(第四行)后,跳出生成器函數。

當調用第二個__next__()方法后,會重新進入生成器函數,并從yield語句的下一條語句(第五行)開始執行,直到重新運行到yield語句,執行后再次跳出生成器函數。

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

3.send()方法:接受外部傳入的一個變量,并根據變量內容計算結果返回到生成器函數中

[注]:

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

(2)第一次調用生成器函數時,必須使用__next__()語句或是send(None),不能使用send發送一個非None的值給生成器函數,否則會出錯,因為沒有yield語句來接收這個值

?
1
2
3
4
5
6
7
8
9
10
11
12
def gen():
  value=0
  while True:
    receive=yield value
    if receive=='end':
      break
    value='Got:%s' %receive
g=gen()
print(g.__next__()) #或是print(g.send(None)),從而啟動生成器
print(g.send('aaa'))
print(g.send(3))
print(g.send('end'))

運行結果:

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__()啟動生成器函數,并執行到第一個yield語句結束的位置并將函數掛起。此時執行完了yield語句,但是沒有給receive賦值,因此yield value會輸出value的初始值0

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def gen():
  while True:
    try:
      yield 'normal value' #返回中間結果,此處的yield和return的功能相似
      yield 'normal value2'
      print('I am here')
    except ValueError:
      print('We got ValueError')
    except Exception:
      print('Other errors')
      break
g=gen()
print(g.__next__())
print(g.throw(ValueError))
print(g.__next__())
print(g.throw(TypeError))

運行結果:

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__())會輸出normal value,并停在yield 'normal value2'之前

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

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

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

四、生成器的運用

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import time
def consumer(name):
  print('%s準備吃包子啦!' %name)
  while True:
    baozi=yield #接收send傳的值,并將值賦值給變量baozi
    print('包子[%s]來了,被[%s]吃了!' %(baozi,name))
def producer(name):
  c1=consumer('A') #把函數變成一個生成器
  c2=consumer('B')
  c1.__next__()#調用這個方法會走到yield處暫時返回
  c2.__next__()
  print('開始準備做包子啦!')
  for i in range(10):
    time.sleep(1)
    print('做了一個包子,分成兩半')
    c1.send(i)
    c2.send(i)
producer('Tomwenxing')

運行結果:

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

希望本文所述對大家Python程序設計有所幫助。

原文鏈接:http://www.cnblogs.com/duwenxing/p/7396976.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 色依依视频视频在线观看 | 色色色资源站 | 精品福利视频一区二区三区 | 成人免费淫片95视频观看网站 | 6080窝窝理论| 国内自拍2019 | 国产91一区二区在线播放不卡 | 黄色大片网 | 天堂网在线网站成人午夜网站 | 114毛片免费观看网站 | 日韩一区二区三区四区不卡 | 2020国产精品亚洲综合网 | 国产精品一区二区久久不卡 | 免费观看国产精品 | 国产精品va在线观看无 | 男同激情视频 | 日本红色高清免费观看 | 性插图动态图无遮挡 | 侵犯小男生免费视频网站 | 青青草原手机在线视频 | 国产麻豆网| 成人福利在线视频免费观看 | 我的好妈妈7中字在线观看韩国 | 久久久大香菇 | 国产福利在线观看第二区 | 日韩a一级欧美一级 | 韩国美女被的免费视频 | 人皮高跟鞋在线观看 | 天堂在线中文无弹窗全文阅读 | 男人的天堂久久精品激情a 男人的天堂va | 亚洲国产精品网站久久 | 日韩欧美在线视频一区二区 | 236宅宅2021最新理论 | 亚洲精品成人456在线播放 | 精品国产欧美一区二区 | 调教处男 | 亚洲精品国产在线观看 | freefron性中国国产高清 | 四虎免费在线观看视频 | 男人日女人的b | 色综合图区 |