堅持原創輸出,點選藍字關注我吧
作者:清菡
部落格:oschina、雲+社群、知乎等各大平臺都有。
由於微信公眾號推送改為了資訊流的形式,防止走丟,請給加個星標 ⭐,你就可以第一時間接收到本公眾號的推送!
目錄
- 一、往期回顧
- 1.生成器程式碼詳解
- 2.生成器的三個方法
- 二、遞迴函式
- 1.什麼是遞迴函式
- 2.遞迴函式呼叫原理圖
- 3.遞迴邊界
- 4.通過遞迴函式實現的任意數的階乘
- 5.這個遞迴函式的遞迴臨界點在哪?
- 6.斐波那契數列
- 三、系列推薦
一、往期回顧
1.生成器程式碼詳解
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
。
2.生成器的三個方法
# 生成器的三個方法: 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()
一樣,去獲取生成器裡面的內容。
2.1next()
獲取生成器裡面的內容:
# 生成器的三個方法: 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))
2.2send()
在呼叫了一次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
關鍵字的。
2.3close()
:關閉生成器
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))
2.4throw()
方法:在生成器內部主動引發一個異常。引數:1.異常型別。2.異常資訊。
這個方法可以接收 2 個引數,第一個引數:Exception
異常型別。第二個引數:傳入異常的資訊。
Exception 報錯:
g.throw(Exception,"Method throw called!")
ValueError:
g.throw(ValueError,"清菡,大事不好,報錯了,嚶嚶嚶~")
二、遞迴函式
1.什麼是遞迴函式
在函式中呼叫函式自身,我們把這樣的函式叫做遞迴函式。
2.遞迴函式呼叫原理圖
3.遞迴邊界
遞迴邊界:退出遞迴的終止條件。
def func():
print('99999')
func()
func()
在外面呼叫函式,直接陷入一個死迴圈。在函式內部呼叫func()
這個函式,又到def func():
這裡來執行,然後print('99999')
,又func()
呼叫。
不斷得自身呼叫,這樣就造成了死迴圈。
Pycharm 有個檢測機制: 當它內部檢測到這個是個無限遞迴,沒有遞迴臨界點的一個遞迴函式,那麼這個時候,它遞迴多少次之後,會自動給終止了。
使用遞迴函式的時候,一定要注意一個點:就是一定要設定遞迴的邊界。遞迴的邊界就是遞迴函式的終止條件。
如果你不設定遞迴邊界,那麼你定義的遞迴函式就是個死迴圈,一直無限得呼叫自身。
4.通過遞迴函式實現的任意數的階乘
4.1 什麼是階乘?
1 的階乘 | 1 |
---|---|
2 的階乘 | 1 * 2 |
3 的階乘 | 1 * 2 * 3 |
4 的階乘 | 1 * 2 * 3 * 4 |
遞迴能實現的,通過迴圈都能實現。
Python 中遞迴用得不多,不太建議使用遞迴,因為遞迴不太好用,用遞迴還不如用迴圈。
4.2 怎麼去算階乘呢?
定義個函式,算任意數的階乘。傳 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
。
4.3 改成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)
5.這個遞迴函式的遞迴臨界點在哪?
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)
任何遞迴函式,它的原理都是一樣的。定義一個遞迴函式,在遞迴函式裡面它其實就是不斷得呼叫自身,然後設定遞迴函式的時候,一定不能忘了遞迴條件。
6.斐波那契數列
後面的數都是等於前 2 個數相加的結果。
斐波那契數列的第一個數值是 1,第二個數值也是個 1,第三個數等於前兩個數相加的結果(那就是 2),第四個數等於於前兩個數相加的結果(那就是 3)。
[1,1,2,3,5]
以此類推。
三、系列推薦
- 測開入門篇《環境管理、編碼規範、專案結構》
- 資料型別· 第 1 篇《元組和列表的效能分析、命名元組》
- 資料型別第 2 篇「字典和集合的原理和應用」
- 測開之資料型別· 第 3 篇《列表推導式、字典推導式、2 種方式建立生成器》
- 測開之資料型別· 第 4 篇《迭代器、生成器》
公眾號 「清菡軟體測試」 首發,更多原創文章:清菡軟體測試 110+原創文章,歡迎關注、交流,禁止第三方擅自轉載。