日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python生成器详解

發(fā)布時間:2023/12/31 python 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python生成器详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

python生成器和python裝飾器幾乎平起平坐,在python世界中占有重要的地位。如果說python裝飾器是為了讓程序員悄無聲息拓展函數(shù)功能,那么python生成器就是為了讓你的代碼更省資源,更高效!說實話python生成器的抽象程度和靈活程度都要比python裝飾器高,功能也更加強大,所以我也只能暫時比較粗略地說句“python生成器就像一把瑞士軍刀,讓你的代碼更加短小(簡潔)精悍(有力)”。
首先我們來看一段python2環(huán)境下運行的一段代碼:

#注意,在python3.x中range和xrange已被合并,這段代碼運行必須在py2下! for i in range(3):print(i) print('----------') for i in xrange(3):print(i) print('----------')lst1 = [x*x for x in range(3)] lst2 = (x*x for x in range(3))for i in lst1:print(i) print('----------') for i in lst2:print(i)

打印結果如下:

0 1 2 ---------- 0 1 2 ---------- 0 1 4 ---------- 0 1 4

看了這段代碼,你可能會說:python真麻煩,有range又有xrange,有[]又有(),運行結果還一樣。這不是白費事嘛?
那我們現(xiàn)在稍微改動下代碼:

a = range(3) b = xrange(3) print(type(a)) print(a) print(a[0],a[1]) print('---------') print(type(b)) print(b) print(b[0],b[1]) print('---------') lst1 = [x*x for x in range(3)] lst2 = (x*x for x in range(3)) print(type(lst1)) print(type(lst2))

打印結果如下:

<type 'list'> [0, 1, 2] (0, 1) --------- <type 'xrange'> xrange(3) (0, 1) --------- <type 'list'> <type 'generator'>

這里需要說明:range()返回一個列表list,xrange()返回一個生成器;也即[]返回一個列表list而()返回一個生成器。

* 注意:用[]推導出來的是迭代器(Iterables)。用()推導出來的是生成器(Generators)。*

可迭代對象(iterable) 與 迭代器(iterator)

iterable可迭代對象是實現(xiàn)了__iter__()方法的對象。更確切的說,是container.__iter__()方法,該方法返回的是的一個iterator對象,因此你可以從iterable可迭代對象獲得iterator迭代器。

在python中,迭代通常是通過for … in …來完成的,而且只要是可迭代對象(iterable),都能進行迭代。

例如,在下面的遍歷中

for value in something

這個something就是一個可迭代對象(iterable)。比如list,string,file。

對于iterable,我們該關注的是,它是一個能一次返回一個成員的對象(iterable is an object capable of returning its members one at a time),一些iterable將所有值都存儲在內存中,比如list,而另一些并不是這樣,比如我們下面將講到的iterator。

iterator(迭代器)是這樣的對象:實現(xiàn)了無參的__next__() 方法,返回序列中的下一個元素;如果沒有元素,將會拋出StopIteration異常。Python的迭代器也實現(xiàn)了__iter__()方法,所以一個迭代器(iterator)也是可迭代的(iterable)。

iterator.next()是iterator區(qū)別于iterable的關鍵了,它允許我們顯式地獲取一個元素.當調用next()方法時,實際上產生了2個操作:

  • 更新iterator狀態(tài),令其指向后一項,以便下一次調用;
  • 返回當前結果;
  • 二者的關系如下 :

    iter(可迭代對象) 生成迭代器

    >>> s = 'abc' #s是一個可迭代對象 >>> it = iter(s) #it是一個迭代器 >>> for i in it: ... print(i)

    我們現(xiàn)在不用for循環(huán)遍歷這個迭代器,我們嘗試調用next()方法。

    >>> s = 'abc' >>> it = iter(s) >>> next(it) 'a' >>> s = 'abc' >>> it = iter(s) >>> next(it) 'a' >>> next(it) 'b' >>> next(it) 'c' >>> next(it) Traceback (most recent call last):File "<stdin>", line 1, in <module> StopIteration >>>

    除了最后一行拋出異常外,其他結果和for循環(huán)一樣。也就是說,用for循環(huán)遍歷迭代器(iterator)X時,會循環(huán)地調用X的next()方法取得每一次的值,直到iterator為空,返回的StopIteration作為循環(huán)結束的標志。for … in … 會自動處理StopIteration異常,從而避免了拋出異常而使程序中斷。

    我們對一個可迭代對象(iterable)用for … in …進行迭代時,實際是先通過調用iter()方法得到一個iterator,假設叫做X.然后循環(huán)地調用X的next()方法取得每一次的值,直到iterator為空,返回的StopIteration作為循環(huán)結束的標志.for … in … 會自動處理StopIteration異常,從而避免了拋出異常而使程序中斷.

    需要格外注意的是,iterator是消耗型的,即每一個值被使用過后,就消失了.因此,你可以將以上的操作2理解成pop.對iterator進行遍歷之后,其就變成了一個空的容器了,但不等于None哦.因此,若要重復使用iterator,利用list()方法將其結果保存起來是一個不錯的選擇。
    代碼如下:

    >>> from collections import Iterable, Iterator >>> a = [1,2,3] # 眾所周知,list是一個iterable >>> b = iter(a) # 通過iter()方法,得到iterator,iter()實際上調用了__iter__(),此后不再多說 >>> isinstance(a, Iterable) True >>> isinstance(a, Iterator) False >>> isinstance(b, Iterable) True >>> isinstance(b, Iterator) True # 可見,itertor一定是iterable,但iterable不一定是itertor# iterator是消耗型的,用一次少一次.對iterator進行變量,iterator就空了! >>> c = list(b) >>> c [1, 2, 3] >>> d = list(b) >>> d []# 空的iterator并不等于None. >>> if b: ... print(1) ... 1 >>> if b == None: ... print(1) ...# 再來感受一下next() >>> e = iter(a) >>> next(e) #next()實際調用了__next__()方法,此后不再多說 1 >>> next(e) 2

    生成器概念

    只要 Python 函數(shù)的定義體中有 yield 關鍵字,該函數(shù)就是生成器函數(shù)。調用生成器函數(shù)時,會返回一個生成器對象。也就是說,生成器函數(shù)是生成器工廠。

    函數(shù)返回一個值,而生成器函數(shù)生成一個值。不僅如此,函數(shù)返回值后就退出了,而生成器可以生產多次值,生成器函數(shù)中還能出現(xiàn)多個yield。

    如何“生成”生成器

    如何產生一個生成器呢,方法有二:

    1.生成器函數(shù)(generator function):帶有yield關鍵字的函數(shù)就是生成器函數(shù),它的返回值是個生成器。
    2.生成器表達式(generator expression):而形如(elem for elem in [1, 2, 3])的表達式,稱為generator expression,也能產生一個生成器。

    生成器表達式生成生成器:

    >>> gen = ( i for i in [2,3,4,5,6]) >>> gen <generator object <genexpr> at 0x00000178D648D1A8> >>> for i in gen: ... print(i) ... 2 3 4 5 6

    我們調用next()方法,也是可以的:

    >>> gen = ( i for i in [2,3,4,5,6]) >>> next(gen) 2 >>> next(gen) 3 >>> next(gen) 4 >>> next(gen) 5 >>> next(gen) 6 >>> next(gen) Traceback (most recent call last):File "<stdin>", line 1, in <module> StopIteration

    這和我們上面迭代器(iterator)的使用一毛一樣!
    其實,生成器(generator)就是迭代器(iterator)的一種,以更優(yōu)雅的方式實現(xiàn)的iterator,而且完全可以像使用iterator一樣使用generator。當然除了定義,定義一個iterator,你需要分別實現(xiàn)_ _ iter _ _ ()方法和 _ _ next_ _()方法,但generator只需要一個yield關鍵字就可以。

    生成器函數(shù)產生生成器

    >>> def gen123(): ... yield 1 ... yield 2 ... yield 3 ... >>> gen123 <function gen123 at 0x00000178D6614D08> >>> gen123() <generator object gen123 at 0x00000178D648D1A8> >>> for i in gen123(): ... print(i) ... 1 2 3

    這里你也能猜出來,我們調用next()方法除了會拋出異常,效果也一樣:

    >>> def gen123(): ... yield 1 ... yield 2 ... yield 3 ... >>> gen = gen123() >>> next(gen) 1 >>> next(gen) 2 >>> next(gen) 3 >>> next(gen) Traceback (most recent call last):File "<stdin>", line 1, in <module> StopIteration

    其實 ,for循環(huán)會每次隱時調用next()方法,前進到函數(shù)中的下一個yield語句處。

    生成器函數(shù)執(zhí)行過程

    生成器另外一個黑科技是生成器中的yield語句會掛起該生成器函數(shù)的狀態(tài),保留足夠的信息,以便之后從它離開的地方繼續(xù)執(zhí)行。

    我們來看代碼:

    >>> def genAB(): #? ... print('start') ... yield 'A' #? ... print('continue') ... yield 'B' #? ... print('end') #? ... >>> for i in genAB(): #? ... print('--->',i) #? ...

    打印結果:

    start ---> A continue ---> B end

    ? 定義生成器函數(shù)的方式與普通的函數(shù)無異,只不過要使用 yield 關鍵字。
    ? 在 for 循環(huán)中第一次隱式調用 next() 函數(shù)時(序號?),會打印
    ‘start’,然后停在第一個 yield 語句,生成值 ‘A’。
    ? 在 for 循環(huán)中第二次隱式調用 next() 函數(shù)時,會打印
    ‘continue’,然后停在第二個 yield 語句,生成值 ‘B’。
    ? 第三次調用 next() 函數(shù)時,會打印 ‘end.’,然后到達函數(shù)定義體
    的末尾,導致生成器對象拋出 StopIteration 異常。
    ? 迭代時,for 機制的作用與 g = iter(gen_AB()) 一樣,用于獲取
    生成器對象,然后每次迭代時調用 next(g)。
    ? 循環(huán)塊打印 –> 和 next(g) 返回的值。但是,生成器函數(shù)中的
    print 函數(shù)輸出結果之后才會看到這個輸出。
    ? ‘start’ 是生成器函數(shù)定義體中 print(‘start’) 輸出的結果。
    ? 生成器函數(shù)定義體中的 yield ‘A’ 語句會生成值 A,提供給 for 循
    環(huán)使用,而 A 會賦值給變量 i,最終輸出 –> A。
    ? 第二次調用 next(g),繼續(xù)迭代,生成器函數(shù)定義體中的代碼由
    yield ‘A’ 前進到 yield ‘B’。文本 continue 是由生成器函數(shù)定義
    體中的第二個 print 函數(shù)輸出的。
    ? yield ‘B’ 語句生成值 B,提供給 for 循環(huán)使用,而 B 會賦值給變
    量 c,所以循環(huán)打印出 –> B。
    ? 第三次調用 next(it),繼續(xù)迭代,前進到生成器函數(shù)的末尾。文本
    end. 是由生成器函數(shù)定義體中的第三個 print 函數(shù)輸出的。到達生成
    器函數(shù)定義體的末尾時,生成器對象拋出 StopIteration 異常。for
    機制會捕獲異常,因此循環(huán)終止時沒有報錯。

    總結

    以上是生活随笔為你收集整理的python生成器详解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。