做者:清菡
博客:oschina、雲+社區、知乎等各大平臺都有。python
因爲微信公衆號推送改成了信息流的形式,防止走丟,請給加個星標 ⭐,你就能夠第一時間接收到本公衆號的推送!微信
def gen(): for i in range(5): j = yield i print(j) # send:與生成器進行交互 g = gen() print(next(g)) print(next(g))
第一個print(next(g))
打印的 0,就是生成器生成的元素。第二個print(next(g))
打印的 1 也是生成器生成的元素,None 是print(j)
打印的j
。網絡
經過生成器獲取元素的時候,首先生成器進去的話,當調用生成器獲取裏面的值,它會從上往下走,走到j = yield i
這裏,把yield
這裏的i
這個值返回出來,調用完gen()
返回一個生成器g
。函數
經過這個生成器next(g)
去拿值的時候,而後它從上往下執行代碼,走到j = yield i
這裏,yield
至關於把i
,經過yield
返回出去。性能
從生成器裏面返回出來,就生成一個數據。生成這個i
,到第一個print(next(g))
這裏,打印的就是i
。測試
第二個print(next(g))
,再用next()
調用生成器的時候,那麼這個生成器會從yield
以後繼續往下執行。編碼
經過next()
去觸發生成器的時候,yield
以後是沒有內容的,j
接收的就是空的,因此打印j
的時候,打印出來的是個None
。code
# 生成器的三個方法: send close throw def gen(): for i in range(5): j = yield i print(j) # send:與生成器進行交互 g = gen() print(g.send(100)) print(next(g)) print(next(g))
運行後報錯:遞歸
生成器的send()
方法,它運行的時候會從上一個yield
結束的地方來進行運行。圖片
在這裏只建立了gen()
這個生成器,這個生成器尚未生成過任何數據,這個時候生成器就暫停在函數最開始的地方def gen():
這裏。
這裏send(100)
這個值進去的話,在這裏運行,直接運行for i in range(5):
這個語句,send(100)
生成進去的這個值沒有地方接收,因此報錯了。
send()
必須在調用了一次next()
以後才調用。能夠和next()
同樣,去獲取生成器裏面的內容。
next()
獲取生成器裏面的內容:# 生成器的三個方法: send close throw def gen(): for i in range(5): j = yield i print(j) # send:與生成器進行交互 g = gen() print(next(g)) print(next(g)) # print(g.send(100))
send()
在調用了一次next()
以後調用,獲取生成器裏面的內容:# 生成器的三個方法: send close throw def gen(): for i in range(5): j = yield i print(j) # send:與生成器進行交互 g = gen() print(next(g)) print(g.send(100)) # print(next(g))
yield
只能在函數裏面用。yield
關鍵字是用在建立生成器的時候,只要函數裏面使用了yield
關鍵字,在調用函數的時候,函數不會立馬被執行。
由於這個函數不是簡單的函數了,它是個生成器。
在函數外面,是沒辦法用yield
關鍵字的。
close()
:關閉生成器def gen(): for i in range(5): j = yield i print(j) yield 100 # send:與生成器進行交互 g = gen() print(next(g)) # print(next(g)) # print(g.send(100)) # close:關閉生成器 g.close() print(next(g))
throw()
方法:在生成器內部主動引起一個異常。參數:1.異常類型。2.異常信息。這個方法能夠接收 2 個參數,第一個參數:Exception
異常類型。第二個參數:傳入異常的信息。
Exception 報錯:
g.throw(Exception,"Method throw called!")
ValueError:
g.throw(ValueError,"清菡,大事很差,報錯了,嚶嚶嚶~")
在函數中調用函數自身,咱們把這樣的函數叫作遞歸函數。
遞歸邊界:退出遞歸的終止條件。
def func(): print('99999') func() func()
在外面調用函數,直接陷入一個死循環。在函數內部調用func()
這個函數,又到def func():
這裏來執行,而後print('99999')
,又func()
調用。
不斷得自身調用,這樣就形成了死循環。
Pycharm 有個檢測機制: 當它內部檢測到這個是個無限遞歸,沒有遞歸臨界點的一個遞歸函數,那麼這個時候,它遞歸多少次以後,會自動給終止了。
使用遞歸函數的時候,必定要注意一個點:就是必定要設置遞歸的邊界。遞歸的邊界就是遞歸函數的終止條件。
若是你不設置遞歸邊界,那麼你定義的遞歸函數就是個死循環,一直無限得調用自身。
1 的階乘 | 1 |
---|---|
2 的階乘 | 1 * 2 |
3 的階乘 | 1 * 2 * 3 |
4 的階乘 | 1 * 2 * 3 * 4 |
遞歸能實現的,經過循環都能實現。
Python 中遞歸用得很少,不太建議使用遞歸,由於遞歸不太好用,用遞歸還不如用循環。
定義個函數,算任意數的階乘。傳 1,就算 1 的階乘,傳 10 就算 10 的階乘。
能夠這樣作:
首先要判斷下它傳進來的這個參數是否是等於 1,若是是等於 1 的話,就直接給它return
返回出去。而後,若是它不等於 1 的話,就返回return n * (n-1)*(n-2)
。
n 傳進來是 1,那應該返回 1;若是傳的是 2,應該返回return n * (n-1)
。
若是在這裏用遞歸函數,調用func(1)
。那麼這個時候,這個func(1)
調用遞歸函數。
這個函數返回的是什麼?
調用這段代碼:
if n == 1: return 1
返回的是個 1。
將代碼修改爲以下:
def fun(n): if n == 1: return 1 else: return n * fun(n-1) fun(3)
若是是fun(3)
,3 傳進來:
def fun(n): if n == 1: return 1
確定是不成立的。
else
後面的代碼return n * fun(n-1)
。
這裏的 n 是個 3,fun(n-1)
就是fun(2)
,那麼就是3 * fun(2)
。
這個時候會再次調用自身這個函數:
這個時候 n 是什麼?
fun(2)
的時候 n 是個 2,就是3 *2* fun(1)
。 fun(1)
再執行下,出來的結果是個 1。那這裏就是個 1,就是3*2*1
。
等於 3 的時候,返回的結果就是3*2*1
。
fun(4)
看看:首先 4 進來,n 等於 4,fun(n-1)
就是fun(3)
。調用fun(3)
就至關於再次調用fun(n)
,就是4 *3* fun(2)
。
再次調用fun(2)
,再進來,前面return n * fun(n-1)
這一截獲得 2,fun(3-1)
獲得 2,因此最終獲得4*3*2* fun(1)
。
fun(1)
調用,結果出來就是個 1。就是4*3*2*1
。
def fun(n): if n == 1: return 1 else: return n * fun(n-1) # 4 *3*2*1 fun(4)
if n == 1: return 1
當n=1
的時候就不會調用自身了。當知足某個條件,再也不調用自身,那麼這個就被稱爲遞歸臨界點。
例如改爲n==-1
if n == -1: return 1
這個時候,這個函數的遞歸臨界點在哪?
這個遞歸臨界點就是-1
。
def fun(n): if n == -1:# 遞歸臨界點:當達到遞歸臨界點的時候,就再也不調用自身函數的條件 return 1 else: return n * fun(n-1) # 4 *3*2*1 fun(4)
任何遞歸函數,它的原理都是同樣的。定義一個遞歸函數,在遞歸函數裏面它其實就是不斷得調用自身,而後設置遞歸函數的時候,必定不能忘了遞歸條件。
後面的數都是等於前 2 個數相加的結果。
斐波那契數列的第一個數值是 1,第二個數值也是個 1,第三個數等於前兩個數相加的結果(那就是 2),第四個數等於於前兩個數相加的結果(那就是 3)。
[1,1,2,3,5]
以此類推。
公衆號 「清菡軟件測試」 首發,更多原創文章:清菡軟件測試 110+原創文章,歡迎關注、交流,禁止第三方擅自轉載。