搜尋
首頁後端開發Python教學一文詳解python生成器

本篇文章為大家帶來了關於python的相關知識,其中主要介紹了關於生成器的相關問題,包括了生成器的概念、生成器的執行過程、yield以及生成器方法等內容,下面一起來看一下,希望對大家有幫助。

一文詳解python生成器

推薦學習:python影片教學

#本篇文章為大家帶來了關於Python的相關知識,其中主要介紹了關於生成器的相關問題,包括了生成器的概念、生成器的執行過程、yield以及生成器方法等內容,下面一起來看一下,希望對大家有幫助。

1. 生成器概念

生成器(英文:generator)是一個非常迷人的東西,也常被認為是 Python 的高階程式設計技能。不過,我依然很

樂意在這裡跟讀者——儘管你可能是個初學者——探討這個話題,因為我相信各位大佬看本教程的目的,絕非僅僅將自己限制於初學者水平,一定有一顆不羈的心——要成為Python 高手。那麼,開始了解生成器吧。

還記得上節的「迭代器」嗎?生成器和迭代器有著一定的淵源關係。生成器必須是可迭代的,誠然它又不僅僅是

迭代器,但除此之外,又沒有太多的別的用途,所以,我們可以把它理解為非常方便的自定義迭代器。

2. 簡單的生成器

>>> my_generator = (x*x for x in range(4))

這是不是跟列表解析很類似呢?仔細觀察,它不是列表,如果這樣的得到的才是列表:

>>> my_list = [x*x for x in range(4)]

以上兩的區別在於是 [] 還是 () ,雖然是細小的差別,但是結果完全不一樣。

>>> dir(my_generator)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__',
'__iter__',
'__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running',
'next',
'send', 'throw']

為了容易觀察,我將上述結果進行了重新排版。是不是發現了在迭代器中必有的方法 __inter__() 和 next() ,這表示它是迭代器。如果是迭代器,就可以用for 迴圈來依序讀出其值

>>> for i in my_generator:
... print i
...
0
1
4
9
>>> for i in my_generator:
... print i
...

當第一遍循環的時候,將my_generator 裡面的值依次讀出並列印,但是,當再讀一次的時候,就發現沒有任何結果。這種特性也正是迭代器所具有的。

如果對那個列表,就不一樣了:

>>> for i in my_list:
... print i
...
0
1
4
9
>>> for i in my_list:
... print i
...
0
1
4
9

難道產生器就是把列表解析中的 [] 換成 () 就行了嗎?這只是生成器的一種表現形式和使用方法罷了,仿照

列表解析式的命名,可以稱之為「生成器解析式」(或:生成器推導式、生成器表達式)。

生成器解析式是有很多用途的,在不少地方替代列表,是一個不錯的選擇。特別是針對大量值的時候,如上節所說的,列表佔內存較多,迭代器(生成器是迭代器)的優勢就在於少佔內存,因此無需將生成器(或者說是迭代器)實例化為一個列表,直接對其進行操作,方顯示出其迭代的優勢。例如:

>>> sum(i*i for i in range(10))
285

注意觀察上面的 sum() 運算,不要以為裡面少了一個括號,就是這麼寫。是不是很迷人呢?如果列表,你

不得不:

>>> sum([i*i for i in range(10)])
285

               透過產生器解析式而產生的產生器,掩蓋了產生器的一些細節,並且適用領域也有限。下面就要剖析生成器的內部,深入理解這個魔法工具。

3. 定義和執行過程

yield 這個字在漢語中有「生產、生產」之意,在Python 中,它作為一個關鍵字(你在變數、函數、類的名稱中

就不能用這個了),是生成器的標誌。

>>> def g():
... yield 0
... yield 1
... yield 2
...
>>> g
<function></function>

建立了一個非常簡單的函數,跟以往看到的函數唯一不同的地方是用了三個 yield 語句。然後進行下面的操作:

>>> ge = g()
>>> ge
<generator>
>>> type(ge)
<type></type></generator>

上面建立的函數傳回值是一個生成器(generator)類型的物件。

>>> dir(ge)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw']

在這裡看到了 __iter__() 和 next() ,說明它是迭代器。既然如此,當然可以:

>>> ge.next()
0
>>> ge.next()
1
>>> ge.next()
2
>>> ge.next()
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
StopIteration</module></stdin>

從這個簡單例子中可以看出,那個含有 yield 關鍵字的函數回傳值是一個生成器類型的對象,這個生成器物件就是迭代器。

我們把含有 yield 語句的函數稱為生成器。生成器是一種用普通函數語法定義的迭代器。透過上面的例子可以看出,這個生成器(也是迭代器),在定義過程中並沒有像上節迭代器那樣寫__inter__() 和next() ,而是只要用了yield 語句,那個普通函數就神奇般地成為了生成器,也就具備了迭代器的功能特性。

yield 語句的作用,就是在呼叫的時候傳回對應的值。詳細剖析一下上面的運行過程:

1. ge = g() :除了傳回生成器之外,什麼也沒有操作,任何值也沒有被回傳。

2. ge.next() :直到這時候,生成器才開始執行,遇到了第一個 yield 語句,將值返回,並暫停執行(有的稱之

为挂起)。

3. ge.next() :从上次暂停的位置开始,继续向下执行,遇到 yield 语句,将值返回,又暂停。

4. gen.next() :重复上面的操作。

5. gene.next() :从上面的挂起位置开始,但是后面没有可执行的了,于是 next() 发出异常。

从上面的执行过程中,发现 yield 除了作为生成器的标志之外,还有一个功能就是返回值。那么它跟 return 这个返回值有什么区别呢?

4. yield

为了弄清楚 yield 和 return 的区别,我写了两个函数来掩饰:

>>> def r_return(n):
... print "You taked me."
... while n > 0:
... print "before return"
... return n
... n -= 1
... print "after return"
...
>>> rr = r_return(3)
You taked me.
before return
>>> rr
3

从函数被调用的过程可以清晰看出, rr = r_return(3) ,函数体内的语句就开始执行了,遇到 return,将值返

回,然后就结束函数体内的执行。所以 return 后面的语句根本没有执行。这是 return 的特点

下面将 return 改为 yield:

>>> def y_yield(n):
... print "You taked me."
... while n > 0:
...     print "before yield"
...     yield n
...     n -= 1
...     print "after yield"
...
>>> yy = y_yield(3) #没有执行函数体内语句
>>> yy.next() #开始执行
You taked me.
before yield
3 #遇到 yield,返回值,并暂停
>>> yy.next() #从上次暂停位置开始继续执行
after yield
before yield
2 #又遇到 yield,返回值,并暂停
>>> yy.next() #重复上述过程
after yield
before yield
1
>>> yy.next()
after yield #没有满足条件的值,抛出异常
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
StopIteration</module></stdin>

结合注释和前面对执行过程的分析,读者一定能理解 yield 的特点了,也深知与 return 的区别了。

一般的函数,都是止于 return。作为生成器的函数,由于有了 yield,则会遇到它挂起,如果还有 return,遇到它就直接抛出 SoptIteration 异常而中止迭代。

#!/usr/bin/env Python
# coding=utf-8

def fibs(max):
    """
    斐波那契数列的生成器
    """
    n, a, b = 0, 0, 1
    while n <p>运行结果如下:</p><pre class="brush:php;toolbar:false">$ python 21501.py
1 1 2 3 5 8 13 21 34 55

用生成器方式实现的斐波那契数列是不是跟以前的有所不同了呢?大家可以将本教程中已经演示过的斐波那契数列实现方式做一下对比,体会各种方法的差异。

经过上面的各种例子,已经明确,一个函数中,只要包含了 yield 语句,它就是生成器,也是迭代器。这种方式显然比前面写迭代器的类要简便多了。但,并不意味着上节的就被抛弃。是生成器还是迭代器,都是根据具体的使用情景而定。

5. 生成器方法

在 python2.5 以后,生成器有了一个新特征,就是在开始运行后能够为生成器提供新的值。这就好似生成器

和“外界”之间进行数据交流。

>>> def repeater(n):
... while True:
...     n = (yield n)
...
>>> r = repeater(4)
>>> r.next()
4
>>> r.send("hello")
'hello

当执行到 r.next() 的时候,生成器开始执行,在内部遇到了 yield n 挂起。注意在生成器函数中, n = (yield

n) 中的 yield n 是一个表达式,并将结果赋值给 n,虽然不严格要求它必须用圆括号包裹,但是一般情况都这

么做,请大家也追随这个习惯。

当执行 r.send("hello") 的时候,原来已经被挂起的生成器(函数)又被唤醒,开始执行 n = (yield n) ,也就是

讲 send() 方法发送的值返回。这就是在运行后能够为生成器提供值的含义。

如果接下来再执行 r.next() 会怎样?

>>> r.next()

什么也没有,其实就是返回了 None。按照前面的叙述,读者可以看到,这次执行 r.next() ,由于没有传入任何值,yield 返回的就只能是 None.

还要注意,send() 方法必须在生成器运行后并挂起才能使用,也就是 yield 至少被执行一次。如果不是这样:

>>> s = repeater(5)
>>> s.send("how")
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator</module></stdin>

就报错了。但是,可将参数设为 None:

>>> s.send(None)
5

这是返回的是调用函数的时传入的值。

此外,还有两个方法:close() 和 throw()

• throw(type, value=None, traceback=None):用于在生成器内部(生成器的当前挂起处,或未启动时在定

义处)抛出一个异常(在 yield 表达式中)。

• close():调用时不用参数,用于关闭生成器。

推荐学习:python视频教程

以上是一文詳解python生成器的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:CSDN。如有侵權,請聯絡admin@php.cn刪除
Numpy數組與使用數組模塊創建的數組有何不同?Numpy數組與使用數組模塊創建的數組有何不同?Apr 24, 2025 pm 03:53 PM

numpyArraysareAreBetterFornumericalialoperations andmulti-demensionaldata,而learthearrayModuleSutableforbasic,內存效率段

Numpy數組的使用與使用Python中的數組模塊陣列相比如何?Numpy數組的使用與使用Python中的數組模塊陣列相比如何?Apr 24, 2025 pm 03:49 PM

numpyArraySareAreBetterForHeAvyNumericalComputing,而lelethearRayModulesiutable-usemoblemory-connerage-inderabledsswithSimpleDatateTypes.1)NumpyArsofferVerverVerverVerverVersAtility andPerformanceForlargedForlargedAtatasetSetsAtsAndAtasEndCompleXoper.2)

CTYPES模塊與Python中的數組有何關係?CTYPES模塊與Python中的數組有何關係?Apr 24, 2025 pm 03:45 PM

ctypesallowscreatingingangandmanipulatingc-stylarraysinpython.1)usectypestoInterfacewithClibrariesForperfermance.2)createc-stylec-stylec-stylarraysfornumericalcomputations.3)passarraystocfunctions foreforfunctionsforeffortions.however.however,However,HoweverofiousofmemoryManageManiverage,Pressiveo,Pressivero

在Python的上下文中定義'數組”和'列表”。在Python的上下文中定義'數組”和'列表”。Apr 24, 2025 pm 03:41 PM

Inpython,一個“列表” isaversatile,mutableSequencethatCanholdMixedDatateTypes,而“陣列” isamorememory-sepersequeSequeSequeSequeSequeRingequiringElements.1)列表

Python列表是可變還是不變的?那Python陣列呢?Python列表是可變還是不變的?那Python陣列呢?Apr 24, 2025 pm 03:37 PM

pythonlistsandArraysareBothable.1)列表Sareflexibleandsupportereceneousdatabutarelessmory-Memory-Empefficity.2)ArraysareMoremoremoremoreMemoremorememorememorememoremorememogeneSdatabutlesserversEversementime,defteringcorcttypecrecttypececeDepeceDyusagetoagetoavoavoiDerrors。

Python vs. C:了解關鍵差異Python vs. C:了解關鍵差異Apr 21, 2025 am 12:18 AM

Python和C 各有優勢,選擇應基於項目需求。 1)Python適合快速開發和數據處理,因其簡潔語法和動態類型。 2)C 適用於高性能和系統編程,因其靜態類型和手動內存管理。

Python vs.C:您的項目選擇哪種語言?Python vs.C:您的項目選擇哪種語言?Apr 21, 2025 am 12:17 AM

選擇Python還是C 取決於項目需求:1)如果需要快速開發、數據處理和原型設計,選擇Python;2)如果需要高性能、低延遲和接近硬件的控制,選擇C 。

達到python目標:每天2小時的力量達到python目標:每天2小時的力量Apr 20, 2025 am 12:21 AM

通過每天投入2小時的Python學習,可以有效提升編程技能。 1.學習新知識:閱讀文檔或觀看教程。 2.實踐:編寫代碼和完成練習。 3.複習:鞏固所學內容。 4.項目實踐:應用所學於實際項目中。這樣的結構化學習計劃能幫助你係統掌握Python並實現職業目標。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。