欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

理解python中生成器用法

 更新時間:2017年12月20日 14:00:55   投稿:laozhang  
本篇文章給大家詳細介紹了python中的生成器用法以及原理,有興趣的朋友參考學習下吧。

生成器(generator)概念

生成器不會把結(jié)果保存在一個系列中,而是保存生成器的狀態(tài),在每次進行迭代時返回一個值,直到遇到StopIteration異常結(jié)束。

生成器語法

生成器表達式: 通列表解析語法,只不過把列表解析的[]換成()
生成器表達式能做的事情列表解析基本都能處理,只不過在需要處理的序列比較大時,列表解析比較費內(nèi)存。

>>> gen = (x**2 for x in range(5))
>>> gen
<generator object <genexpr> at 0x0000000002FB7B40>
>>> for g in gen:
...  print(g, end='-')
...
0-1-4-9-16-
>>> for x in [0,1,2,3,4,5]:
...  print(x, end='-')
...
0-1-2-3-4-5-

生成器函數(shù): 在函數(shù)中如果出現(xiàn)了yield關(guān)鍵字,那么該函數(shù)就不再是普通函數(shù),而是生成器函數(shù)。

但是生成器函數(shù)可以生產(chǎn)一個無線的序列,這樣列表根本沒有辦法進行處理。

yield 的作用就是把一個函數(shù)變成一個 generator,帶有 yield 的函數(shù)不再是一個普通函數(shù),Python 解釋器會將其視為一個 generator。

下面為一個可以無窮生產(chǎn)奇數(shù)的生成器函數(shù)。

def
odd():
n=1
while
True:
yield
n
n+=2
odd_num
=
odd()
count
=
0
for
o
in
odd_num:
if
count
>=5:
break
print(o)
count
+=1

當然通過手動編寫迭代器可以實現(xiàn)類似的效果,只不過生成器更加直觀易懂

class Iter:
  def __init__(self):
    self.start=-1
  def __iter__(self):
    return self
  def __next__(self):
    self.start +=2 
    return self.start
I = Iter()
for count in range(5):
  print(next(I))

題外話: 生成器是包含有__iter()和next__()方法的,所以可以直接使用for來迭代,而沒有包含StopIteration的自編Iter來只能通過手動循環(huán)來迭代

>>>
from
collections
import
Iterable
>>>
from
collections
import
Iterator
>>>
isinstance(odd_num,
Iterable)
True
>>>
isinstance(odd_num,
Iterator)
True
>>>
iter(odd_num)
is
odd_num
True
>>>
help(odd_num)
Help
on
generator
object:
odd
=
class
generator(object)
| Methods
defined
here:
|
| __iter__(self,
/)
|   Implement
iter(self).
|
| __next__(self,
/)
|   Implement
next(self).
......

到上面的結(jié)果,現(xiàn)在你可以很有信心的按照Iterator的方式進行循環(huán)了吧!

在 for 循環(huán)執(zhí)行時,每次循環(huán)都會執(zhí)行 fab 函數(shù)內(nèi)部的代碼,執(zhí)行到 yield b 時,fab 函數(shù)就返回一個迭代值,下次迭代時,代碼從 yield b 的下一條語句繼續(xù)執(zhí)行,而函數(shù)的本地變量看起來和上次中斷執(zhí)行前是完全一樣的,于是函數(shù)繼續(xù)執(zhí)行,直到再次遇到 yield??雌饋砭秃孟褚粋€函數(shù)在正常執(zhí)行的過程中被 yield 中斷了數(shù)次,每次中斷都會通過 yield 返回當前的迭代值。

yield 與 return

在一個生成器中,如果沒有return,則默認執(zhí)行到函數(shù)完畢時返回StopIteration;

>>> def g1():
...   yield 1
...
>>> g=g1()
>>> next(g)  #第一次調(diào)用next(g)時,會在執(zhí)行完yield語句后掛起,所以此時程序并沒有執(zhí)行結(jié)束。
1
>>> next(g)  #程序試圖從yield語句的下一條語句開始執(zhí)行,發(fā)現(xiàn)已經(jīng)到了結(jié)尾,所以拋出StopIteration異常。
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration
>>>

如果遇到return,如果在執(zhí)行過程中 return,則直接拋出 StopIteration 終止迭代。

>>>
def
g2():
...  
yield
'a'
...  
return
...  
yield
'b'
...
>>>
g=g2()
>>>
next(g)  #程序停留在執(zhí)行完yield
 'a'語句后的位置。
'a'
>>>
next(g)  #程序發(fā)現(xiàn)下一條語句是return,所以拋出StopIteration異常,這樣yield
 'b'語句永遠也不會執(zhí)行。
Traceback
(most
recent
call
last):
 File
"<stdin>",
line
1,
in
<module>
StopIteration

如果在return后返回一個值,那么這個值為StopIteration異常的說明,不是程序的返回值。

生成器沒有辦法使用return來返回值。

>>> def g3():
...   yield 'hello'
...   return 'world'
...
>>> g=g3()
>>> next(g)
'hello'
>>> next(g)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration: world

生成器支持的方法

>>>
help(odd_num)
Help
on
generator
object:
odd
=
class
generator(object)
| Methods
defined
here:
......
| close(...)
|   close()
->
raise
GeneratorExit
inside
generator.
|
| send(...)
|   send(arg)
->
send
'arg'
into
generator,
|   return
next
yielded
value
or
raise
StopIteration.
|
| throw(...)
|   throw(typ[,val[,tb]])
->
raise
exception
in
generator,
|   return
next
yielded
value
or
raise
StopIteration.
......

close()

手動關(guān)閉生成器函數(shù),后面的調(diào)用會直接返回StopIteration異常。

>>> def g4():
...   yield 1
...   yield 2
...   yield 3
...
>>> g=g4()
>>> next(g)
1
>>> g.close()
>>> next(g)  #關(guān)閉后,yield 2和yield 3語句將不再起作用
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

send()

生成器函數(shù)最大的特點是可以接受外部傳入的一個變量,并根據(jù)變量內(nèi)容計算結(jié)果后返回。

這是生成器函數(shù)最難理解的地方,也是最重要的地方,實現(xiàn)后面我會講到的協(xié)程就全靠它了。

def
gen():
  value=0
  while
True:
    receive=yield
value
    if
receive=='e':
      break
    value
=
'got: %s'
%
receive
g=gen()
print(g.send(None)) 
print(g.send('aaa'))
print(g.send(3))
print(g.send('e'))

執(zhí)行流程:

通過g.send(None)或者next(g)可以啟動生成器函數(shù),并執(zhí)行到第一個yield語句結(jié)束的位置。此時,執(zhí)行完了yield語句,但是沒有給receive賦值。yield value會輸出初始值0注意:在啟動生成器函數(shù)時只能send(None),如果試圖輸入其它的值都會得到錯誤提示信息。

通過g.send(‘a(chǎn)aa'),會傳入aaa,并賦值給receive,然后計算出value的值,并回到while頭部,執(zhí)行yield value語句有停止。此時yield value會輸出”got: aaa”,然后掛起。

通過g.send(3),會重復第2步,最后輸出結(jié)果為”got: 3″

當我們g.send(‘e')時,程序會執(zhí)行break然后推出循環(huán),最后整個函數(shù)執(zhí)行完畢,所以會得到StopIteration異常。

最后的執(zhí)行結(jié)果如下:

0
got: aaa
got: 3
Traceback (most recent call last):
File "h.py", line 14, in <module>
 print(g.send('e'))
StopIteration

throw()

用來向生成器函數(shù)送入一個異常,可以結(jié)束系統(tǒng)定義的異常,或者自定義的異常。

throw()后直接跑出異常并結(jié)束程序,或者消耗掉一個yield,或者在沒有下一個yield的時候直接進行到程序的結(jié)尾。

def
gen():
  while
True:
    try:
      yield
'normal value'
      yield
'normal value 2'
      print('here')
    except
ValueError:
      print('we
 got ValueError here')
    except
TypeError:
      break
g=gen()
print(next(g))
print(g.throw(ValueError))
print(next(g))
print(g.throw(TypeError))

輸出結(jié)果為:

normal value
we got ValueError here
normal value
normal value 2
Traceback (most recent call last):
 File "h.py", line 15, in <module>
  print(g.throw(TypeError))
StopIteration

解釋:

print(next(g)):會輸出normal value,并停留在yield ‘normal value 2'之前。

由于執(zhí)行了g.throw(ValueError),所以會跳過所有后續(xù)的try語句,也就是說yield ‘normal value 2'不會被執(zhí)行,然后進入到except語句,打印出we got ValueError here。然后再次進入到while語句部分,消耗一個yield,所以會輸出normal value。

print(next(g)),會執(zhí)行yield ‘normal value 2'語句,并停留在執(zhí)行完該語句后的位置。

g.throw(TypeError):會跳出try語句,從而print(‘here')不會被執(zhí)行,然后執(zhí)行break語句,跳出while循環(huán),然后到達程序結(jié)尾,所以跑出StopIteration異常。

下面給出一個綜合例子,用來把一個多維列表展開,或者說扁平化多維列表)

def
flatten(nested):
  try:
    #如果是字符串,那么手動拋出TypeError。
    if
isinstance(nested,
str):
      raise
TypeError
    for
sublist
in
nested:
      #yield
 flatten(sublist)
      for
element
in
flatten(sublist):
        #yield
 element
        print('got:',
element)
  except
TypeError:
    #print('here')
    yield
nested
L=['aaadf',[1,2,3],2,4,[5,[6,[8,[9]],'ddf'],7]]
for
num
in
flatten(L):
  print(num)

如果理解起來有點困難,那么把print語句的注釋打開在進行查看就比較明了了。

總結(jié)

按照鴨子模型理論,生成器就是一種迭代器,可以使用for進行迭代。

第一次執(zhí)行next(generator)時,會執(zhí)行完yield語句后程序進行掛起,所有的參數(shù)和狀態(tài)會進行保存。再一次執(zhí)行next(generator)時,會從掛起的狀態(tài)開始往后執(zhí)行。在遇到程序的結(jié)尾或者遇到StopIteration時,循環(huán)結(jié)束。

可以通過generator.send(arg)來傳入?yún)?shù),這是協(xié)程模型。

可以通過generator.throw(exception)來傳入一個異常。throw語句會消耗掉一個yield??梢酝ㄟ^generator.close()來手動關(guān)閉生成器。

next()等價于send(None)

相關(guān)文章

  • 聊聊python中的load、loads實現(xiàn)反序列化的問題

    聊聊python中的load、loads實現(xiàn)反序列化的問題

    在python自動化中,我們傳遞一些參數(shù)是需要從文件中讀取過來的,讀取過來的字典并非python對象數(shù)據(jù)類型而是string類型。本文給大家分享python中的load、loads實現(xiàn)反序列化的問題,感興趣的朋友一起看看吧
    2021-10-10
  • 深入理解 Python 中的多線程 新手必看

    深入理解 Python 中的多線程 新手必看

    你應當將下邊的例子運行多次,以便可以注意到線程是不可預測的和線程每次運行出的不同結(jié)果。聲明:從這里開始忘掉你聽到過的關(guān)于GIL的東西,因為GIL不會影響到我想要展示的東西
    2016-11-11
  • python中from module import * 的一個坑

    python中from module import * 的一個坑

    from module import *把module中的成員全部導到了當前的global namespace,訪問起來就比較方便了。當然,python style一般不建議這么做,因為可能引起name conflict。
    2014-07-07
  • 一文詳細介紹Python中pkl格式文件

    一文詳細介紹Python中pkl格式文件

    .pkl文件是Python中用于存儲對象的文件格式,全稱是"pickle",它是Python標準庫中的一個模塊,用于將Python對象序列化,以便于在不同的Python程序之間進行傳輸或存儲,這篇文章主要給大家介紹了如何通過一文詳細介紹Python中pkl格式文件的相關(guān)資料,需要的朋友可以參考下
    2024-05-05
  • 詳解Python中expandtabs()方法的使用

    詳解Python中expandtabs()方法的使用

    這篇文章主要介紹了詳解Python中expandtabs()方法的使用,是Python入門中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-05-05
  • Python讀取CSV文件并計算某一列的均值和方差

    Python讀取CSV文件并計算某一列的均值和方差

    這篇文章主要介紹了利用Python讀取CSV文件并計算某一列的均值和方差,這里利用了csv模塊來對文件進行處理,文章通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • Python Numpy之linspace用法說明

    Python Numpy之linspace用法說明

    這篇文章主要介紹了Python Numpy之linspace用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Django使用Celery加redis執(zhí)行異步任務的實例內(nèi)容

    Django使用Celery加redis執(zhí)行異步任務的實例內(nèi)容

    在本篇文章里小編給大家整理的是關(guān)于Django使用Celery加redis執(zhí)行異步任務,需要的朋友們可以學習下。
    2020-02-02
  • 如何利用python之wxpy模塊玩轉(zhuǎn)微信

    如何利用python之wxpy模塊玩轉(zhuǎn)微信

    這篇文章主要介紹了利用python之wxpy模塊玩轉(zhuǎn)微信,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • 使用python3.0?對接美團接口的實現(xiàn)示例

    使用python3.0?對接美團接口的實現(xiàn)示例

    本文主要介紹了python3.0?對接美團接口的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05

最新評論