Python中yield簡單用法

Python中yield簡單用法

你或許知道帶有yield的函數在Python中被稱之為generator,那何為 generator?

我們暫時拋開generator,先從一個常見編程題目開始,循序漸進了解yield的概念。

生成Fibonacci數列

Fibonacci數列是一個經典遞歸數列,第0個數為0,第1個數為1,除第0個和第1個數外,任意一個數都可由前兩個數相加得到。

Fibonacci數列(版本一)

一種Fibonacci數列簡單實現:

def fab(max):n, a, b = 0, 0, 1while n < max:print ba, b = b, a + bn = n + 1
fab(5)

運行結果:

1
1
2
3
5

結果沒有問題,但有經驗的開發者會指出,直接在fab函數中用print打印數字會導致該函數可復用性較差,因為fab函數返回 None,其他函數無法獲得該函數生成的數列。

要提高fab函數的可復用性,最好不要直接打印出數列,而是返回一個list。那么我們在版本一的基礎上進行修改。

Fibonacci數列(版本二)

def fab(max):n, a, b = 0, 0, 1L = []while n < max:L.append(b)a, b = b, a + bn = n + 1return Lfor n in fab(5):print n

運行結果:

1
1
2
3
5

改寫后的fab函數通過返回List能滿足復用性的要求,但是更有經驗的開發者會指出,該函數在運行中占用的內存會隨著參數max的增大而增大。

如果要控制內存占用,最好不要用List來保存中間結果,而是通過iterable對象來迭代。

例如,在 Python2.x中,代碼:

for i in range(1000): pass

上述代碼會導致生成一個1000個元素的List。

for i in xrange(1000): pass

上述代碼不會生成一個1000個元素的List,而是在每次迭代中返回下一個數值,內存空間占用很小。因為 xrange不返回List,而是返回一個 iterable 對象

利用iterable我們可以把fab函數改寫為一個支持iterable的class,以下是第三個版本的fab:

Fibonacci數列(版本三)

class Fab(object):def __init__(self, max):self.max = maxself.n, self.a, self.b = 0, 0, 1def __iter__(self):return selfdef next(self):if self.n < self.max:r = self.bself.a, self.b = self.b, self.a + self.bself.n = self.n + 1return rraise StopIteration()for n in Fab(5):print n

Fab類通過next()不斷返回數列的下一個數,內存占用始終為常數:

1
1
2
3
5

然而,使用class改寫的這個版本,代碼遠遠沒有第一版的fab函數來得簡潔。如果我們想要保持第一版fab函數的簡潔性,同時又要獲得iterable的效果,yield閃亮登場

Fibonacci數列(版本四)(yield)

def fab(max):n, a, b = 0, 0, 1while n < max:yield b      # 使用 yield# print ba, b = b, a + bn = n + 1for n in fab(5):print n

第四個版本的fab和第一版相比,僅僅把print b改為了yield b,就在保持簡潔性的同時獲得了 iterable的效果。

調用第四版的fab和第二版的fab完全一致:

1
1
2
3
5

簡單地講,yield的作用就是把一個函數變成一個generator,帶有yield的函數不再是一個普通函數,Python解釋器會將其視為一個generator,調用 fab(5)不會執行fab函數,而是返回一個 iterable對象!

在for循環執行時,每次循環都會執行fab函數內部的代碼,執行到yield b時,fab 函數就返回一個迭代值,下次迭代時,代碼從yield b的下一條語句繼續執行,而函數的本地變量看起來和上次中斷執行前是完全一樣的,于是函數繼續執行,直到再次遇到 yield

也可以手動調用fab(5)的next()方法(因為 fab(5) 是一個 generator 對象,該對象具有next()方法),這樣我們就可以更清楚地看到 fab 的執行流程:

>>>f = fab(5)
>>> f.next()
1
>>> f.next()
1
>>> f.next()
2
>>> f.next()
3
>>> f.next()
5
>>> f.next()
Traceback (most recent call last):File "<stdin>", line 1, in <module>
StopIteration

當函數執行結束時,generator自動拋出StopIteration異常,表示迭代完成。在for循環里,無需處理 StopIteration異常,循環會正常結束。

小結

一個帶有 yield 的函數就是一個 generator,它和普通函數不同,生成一個 generator 看起來像函數調用,但不會執行任何函數代碼,直到對其調用next()(在 for 循環中會自動調用 next())才開始執行。雖然執行流程仍按函數的流程執行,但每執行到一個 yield 語句就會中斷,并返回一個迭代值,下次執行時從yield的下一個語句繼續執行。看起來就好像一個函數在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過yield返回當前的迭代值。

yield的好處是顯而易見的,把一個函數改寫為一個generator就獲得了迭代能力,比起用類的實例保存狀態來計算下一個next()的值,不僅代碼簡潔,而且執行流程異常清晰。

特殊的generator函數其他相關

如何判斷一個函數是否是一個特殊的generator函數?可以利用isgeneratorfunction判斷:

>>>import types
>>> isinstance(fab, types.GeneratorType)
False
>>> isinstance(fab(5), types.GeneratorType)
True

要注意區分 fab 和 fab(5),fab 是一個 generator function,而 fab(5) 是調用 fab 返回的一個 generator,好比類的定義和類的實例的區別:

>>>import types
>>> isinstance(fab, types.GeneratorType)
False
>>> isinstance(fab(5), types.GeneratorType)
True

fab 是無法迭代的,而 fab(5) 是可迭代的:

>>>from collections import Iterable
>>> isinstance(fab, Iterable)
False
>>> isinstance(fab(5), Iterable)
True

每次調用 fab 函數都會生成一個新的generator實例,各實例互不影響:

>>>f1 = fab(3)
>>> f2 = fab(5)
>>> print 'f1:', f1.next()
f1: 1
>>> print 'f2:', f2.next()
f2: 1
>>> print 'f1:', f1.next()
f1: 1
>>> print 'f2:', f2.next()
f2: 1
>>> print 'f1:', f1.next()
f1: 2
>>> print 'f2:', f2.next()
f2: 2
>>> print 'f2:', f2.next()
f2: 3
>>> print 'f2:', f2.next()
f2: 5

return的作用

在一個 generator function 中,如果沒有return,則默認執行至函數完畢,如果在執行過程中 return,則直接拋出StopIteration終止迭代。

另一個例子——用在文件讀取的yield

如果直接對文件對象調用read()方法,會導致不可預測的內存占用。好的方法是利用固定長度的緩沖區來不斷讀取文件內容。通過 yield,我們不再需要編寫讀文件的迭代類,就可以輕松實現文件讀取:

def read_file(fpath):BLOCK_SIZE = 1024with open(fpath, 'rb') as f:while True:block = f.read(BLOCK_SIZE)if block:yield blockelse:return

總結

以上僅僅簡單介紹了 yield 的基本概念和用法,yield 在 Python 3 中還有更強大的用法。

參考資料

Python yield 使用淺析

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445837.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445837.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445837.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

js 用下標獲取map值_js map方法處理返回數據,獲取指定數據簡寫方法

map方法處理返回數據&#xff0c;獲取指定數據簡寫方法前言后端返回數據為數組列表時&#xff0c;通常比較全面&#xff0c;包含了很多不需要的數據&#xff0c;可以通過 map 方法處理返回數據&#xff0c;篩選出想要的數據例如// 返回數據res [{id: 1,name: zhangsan,age: 16…

《Python Cookbook 3rd》筆記匯總

文章目錄一、數據結構二、字符串和文本三、數字、日期和時間四、迭代器與生成器五、文件與IO一、數據結構 標題關鍵詞1.1&#xff1a;拆分序列后賦值給多個變量可迭代對象、拆分賦值1.2&#xff1a;拆分任意長可迭代對象后賦值給多個變量可迭代對象、拆分賦值、星號表達式1.3&…

mysql hp ux_hp ux apa 切換

(HP-UX Only) OR - 1 heartbeat network using APA with 2 trunk members (HP-UX Only) OR - 1 heartbeat network with serial line (HP-UX Only) OR......一、 概述 HP 的 APA 軟件提供兩種網卡冗余切換模式,用以實現網絡高可用性...0x000000000000 hp_apa HP-UX 11i v3 Prer…

Python中[:]與[::]的用法

Python中[:]與[::]的用法 概述 [:]與[::]語法是通用序列操作&#xff08;Common Sequence Operations&#xff09;其中的兩個。用[:]或[::]對多數序列類型&#xff08;可變的或不可變的&#xff09;&#xff08;如字符串、列表等&#xff09;序列中元素進行截取。 [:]的用法…

mysql redis 中間件_Docker快速搭建Mysql社區版,Redis,MongoDb、MQ等等中間件。

一&#xff1a;安裝docker社區版。Centos系列(最好用7以上的版本&#xff0c;docker需要3.1以上的linux內核版本)sudo yum install docker-ce docker-ce-cli containerd.iosudo systemctl start dockersudo docker run hello-world如果你敲docker info需要root密碼&#xff0c;…

JavaScript中String的slice(),substr(),substring()三者區別

JavaScript中String的slice()&#xff0c;substr()&#xff0c;substring()三者區別 共同之處 從給定的字符串中截取片段&#xff0c;并返回全新的這片段的字符串對象&#xff0c;且不會改動原字符串。 具體不同之處 slice() str.slice(beginIndex[, endIndex])參數描述be…

pythontuple數據類型_數據類型-元組Tuple

Python Tuple用于存儲不可變python對象的序列。元組類似于列表&#xff0c;因為可以改變列表中存儲的項的值&#xff0c;而元組是不可變的&#xff0c;并且不能改變存儲在元組中的項的值。元組可以寫成用小括號括起來的逗號分隔值的集合。元組可以定義如下。T1 (101, "Ay…

《劍指Offer》24:反轉鏈表

題目 定義一個函數&#xff0c;輸入一個鏈表的頭節點&#xff0c;反轉鏈表并輸出反轉后鏈表的頭節點。鏈表節點定義如下&#xff1a; public static class ListNode{public int val;public ListNode next;public ListNode(int val) {this.val val;} }分析 方法一&#xff1…

python兩個for循環為什么第二個循環里值不變_兩個for循環,第二個只在第一個迭代python上執行...

我是一個pythonnoob&#xff0c;我試圖比較兩個文件中的行之間的值&#xff0c;如果行在第二個文件中&#xff0c;則輸出“line name”&#xff0c;然后輸出1&#xff1b;如果第二個文件中缺少該行&#xff0c;則輸出0。第一次迭代返回1&#xff0c;因為該行在第二個文件中&…

python如何問問題_學會正確的提問

可能很多讀者看到這個標題會感覺很可笑&#xff0c;提問誰不會啊&#xff0c;互聯網時代&#xff0c;提問還不是一句話的事情&#xff1f;個人、技術群、論壇里都可以提問啊&#xff0c;「你好」「在嗎&#xff1f;」「有人用過 xx 工具嗎&#xff1f;」。首先&#xff0c;提問…

如何保證接口的冪等性

如何保證接口的冪等性 什么是冪等性 冪等性是系統服務對外一種承諾&#xff0c;承諾只要調用接口成功&#xff0c;外部多次調用對系統的影響是一致的。聲明為冪等的服務會認為外部調用失敗是常態&#xff0c;并且失敗之后必然會有重試。 通俗地說&#xff0c;接口冪等性就是…

mysql二進制方式_MySQL數據庫之MySql二進制連接方式詳解

本文主要向大家介紹了MySQL數據庫之MySql二進制連接方式詳解 &#xff0c;通過具體的內容向大家展現&#xff0c;希望對大家學習MySQL數據庫有所幫助。使用mysql二進制方式連接您可以使用MySQL二進制方式進入到mysql命令提示符下來連接MySQL數據庫。實例以下是從命令行中連接my…

xposed模塊編寫教程_太極xposed模塊使用教程

今天給大家分享一下太極xposed模塊使用教程。很多小伙伴說下載不到Xposed模塊&#xff0c;這個網上其實很多&#xff0c;但是第三方的下載站就算了吧。我也是一個深受其害的網癮少年&#xff0c;只要是下載站的軟件&#xff0c;一不留心一次性電腦可能會多安裝好多個軟件&#…

如何使用mysql添加更新_Mysql 存在既更新,不存在就添加(sql語句)

討人喜歡的 MySQL replace into 用法(insert into 的增強版)在向表中插入數據的時候&#xff0c;經常遇到這樣的情況&#xff1a;1. 首先判斷數據是否存在&#xff1b; 2. 如果不存在&#xff0c;則插入&#xff1b;3.如果存在&#xff0c;則更新。在 SQL Server 中可以這樣處理…

linux + nginx + mysql + php 百度網盤_5.LNMP(Linux + Nginx + MySQL + PHP)環境安裝

1.安裝Nginx:yum install yum-priorities -ywget http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpmrpm -ivh nginx-release-centos-7-0.el7.ngx.noarch.rpmyum -y install nginxsystemctl start nginx.servicesystemctl stop ngin…

LeetCode - Easy - 28. Implement strStr()

Topic Two Pointers, String Description https://leetcode.com/problems/implement-strstr/ Implement strStr(). Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. needle /?ni?dl/ n.針 haystack /?he?…

mysql item_MySQL源代碼:關于MySQL的Item對象

前篇介紹了MySQL如何從SQL語句轉換成一個內部對象。本文是前篇的延續&#xff0c;將更加詳細的介紹WHERE語句對應的Item對象。1. Item對象MySQL InternalMySQL Internals Manual較為詳細的介紹了Item對象。Item對象經常被稱作"thingamabob"(A thingamabob is a noun …

python的發展趨勢圖_用Python繪制趨勢圖

我在數據幀中有以下數據&#xff1a;-------------------------------------------------------| Physician Profile Id | Program Year | Value Of Interest |-------------------------------------------------------| 1004777 | 2013 | 83434288.00 || 1004777 | 2014 | 89…

mysql的實現類注解_Mybaits (XML方式:無需在寫Dao的實現類 注解方式:Dao的實現類與Mapper都可以不寫 重點理解)...

Maven的pom.xml 坐標配置4.0.0Mybatis_mavenday01_mbatis1.0-SNAPSHOTjarorg.mybatismybatis3.4.5mysqlmysql-connector-java5.1.45junitjunit4.12testorg.apache.maven.pluginsmaven-compiler-plugin2.3.21.81.8UTF-8mybatis的配置文件/p>PUBLIC "-//mybatis.org//DTD…

SQL字符串中單引號與換行符的轉義

問題 打算將文本文件內容添加至MySQL數據庫&#xff0c;則需要對文本中的單引號和換行符進行轉義&#xff0c;否則無法編寫合法的SQL。 解法 迭代文本文件的行時&#xff0c;將原行尾的換行符剔除掉&#xff0c;并拼接\\n;迭代文本文件的行時&#xff0c;將原行中的替換成。…