python系列4
目錄
- 遞歸算法解析
- 冒泡排序解析
- 裝飾器解析
一. 遞歸
1. 遞歸的定義
遞歸(Recursion),又成為遞回,在數學與計算機科學中,是指在函數的定義中使用函數自身的方法。遞歸一詞還較長用於描述以自相似方法重復事物的過程。
斐波那契數列是典型的遞歸案例: F0 = 0(初始值) F1 = 1(初始值) 對所有大於1的整數n: F(n) = F(n - 1) + F(n - 2)(遞歸定義) 盡管有許多數學函數均可以遞歸表示,但在實際應用中,遞歸的開銷過大,因此在不是必要的情況下最好不要用到遞歸。
2. 遞歸的原理
(1). 例題:
def recursion(defth, a1, a2):if defth == 5: return a1 a3 = a1 + a2 defth = defth + 1 print(a1) a1 = recursion(defth, a2, a3) return a1 ret = recursion(1, 0, 1) print(ret)
以下這幅圖為整個函數的執行過程,紅色的代表一層一層的往裏面嵌套,綠色的代表函數的返回值一層一層的外面返還。其實遞歸就是這個原理,通過一個函數的執行流在再次進入此函數,當通過一個條件返回一個值之後,一層一層的按照剛剛的執行流再次返回回去,最後得到返回值,但是遞歸的時候要註意兩點:
1. 他的條件,必須要使他的遞歸在某個條件內可以返回一個值,否則就會一直遞歸,直到電腦資源耗盡(Python默認有遞歸的次數限制)
2. 返回值,在裏面的遞歸函數一般要給予他一定的返回值,否則在最後一次返還遞歸的時候會得不到想要的值。
二. 冒泡排序
1. 冒泡排序原理
冒泡排序就是一種簡單的排序算法。他重復的走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。
冒泡排序算法的運作如下: 1. 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。 2. 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步做完後,最後的元素會是最大的數。 3. 針對所有的元素重復以上的步驟,除了最後一個。 4. 持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較
交換數據的原理
借助一個外圍的變量先保存原來的值,然後再去通過指向地址的轉換來進行交換數據。註意:當temp指向了a, 然後a再指向b的時候,temp本身的指向是沒有發生改變的,就如下圖,a指向了b,但是temp依然指向的是a的地址,所以他還是66
a = 66 b = 88 temp = a a = b b = temp
冒泡排序的原理
2. 冒泡排序事例
1 # -*- coding:utf-8 -*- 2 # zhou 3 # 2017/6/17 4 list = [0, 88, 99, 33, 22, 11, 1] 5 for j in range(1, len(list)): 6 for i in range(len(list) - j): 7 # 如果第一個數據大, 則交換數據, 否則, 不做改變 8 if list[i] > list[i + 1]: 9 temp = list[i] 10 list[i] = list[i + 1] 11 list[i + 1] = temp 12 print(list)
三. 裝飾器
1. 裝飾器定義
裝飾器是什麽呢?簡單來說就是在不改變源函數代碼的基礎上,對代碼的一種微妙的擴展,以使得其功能進一步增強的函數。裝飾器就是一個函數,一個加載在其他函數之上的函數,
以下我們先來了解幾個概念:
<1>. 函數執行流
由以上面的可知,函數的執行流應該是從上到下的,也就是說,代碼先把第一個test1加載到內存中,然後從新開辟一塊內存來存放第二個test1。
這裏應該是第一個test1的指向改到了890673481792這裏。
def test1(): print(‘日本人.‘) print(id(test1)) def test1(): print(‘中國人.‘) print(id(test1)) test1() 執行結果: 890673481656 890673481792 中國人.
<2>. 函數作為變量
由以下結果可以看出來,函數名其實就是一個變量,可以用來傳遞的變量。
註意:函數作為變量的時候不能加括號,必須只是函數名
def test1(): print(‘我是.‘) a = test1 print(a) print(test1)
結果: <function test1 at 0x000000E2D403C7B8> <function test1 at 0x000000E2D403C7B8>
<3>. 函數嵌套
這裏定義了三個函數,test1,test2,test3, 3裏面嵌套了1, 1裏面又嵌套了2,從他的結果中想必你也會看出來函數的執行流。
def test1(): print(‘我是‘,end=‘‘) def test2(): print(‘中國人.‘) test2() def test3(): test1() print(‘Hello, China.‘) test3() 結果: 我是中國人. Hello, China.
2. 裝飾器原理
(1). 裝飾器的寫法和使用
<1>. 裝飾器也是一個函數
<2>. 使用裝飾器的格式: 在一個函數前面加上:@裝飾器的名字
(2). 裝飾器的原理
<1>. 把test1函數當做一個變量傳入outer中
func = test1
<2>. 把裝飾器嵌套的一個函數inner賦值給test1
test1 = inner
<3>. 當執行test1函數的時候,就等於執行了inner函數,因此在最後的那個test1()命令其實執行的就是inner,因此先輸出(你是哪國人)
<4>. 按照執行流執行到func函數的時候,其實執行的就是原來的test1函數,因此接著輸出(我是中國人),並把它的返回值返回給了ret
<5>. 當原來的test1函數執行完了之後,繼續執行inner裏面的命令,因此輸出了(Oh,hh, I love China.)
(3). 裝飾器的總結
由上面的執行流可以看出來,其實裝飾器把之前的函數當做參數傳遞進去,然後創建了另一個函數用來在原來的函數之前或者之後加上所需要的功能。
# -*- coding:utf-8 -*- # zhou # 2017/6/17
# 定義了一個裝飾器outer
def outer(func): def inner(): print(‘你是哪國人?‘) ret = func() print(‘Oh, hh, I love China.‘) return inner @outer def test1(): print(‘我是中國人.‘) test1()
3. 帶參數的裝飾器
為了裝飾器的高可用,一般都會采用下面的方式,也就是無論所用的函數是多少個參數,這個裝飾器都可以使用
Python內部會自動的分配他的參數。
# -*- coding:utf-8 -*- # zhou # 2017/6/17 def outer(func): def inner(a, *args, **kwargs): print(‘你是哪國人?‘) ret = func(a, *args, **kwargs) print(‘Oh, hh, I love China.‘) return inner @outer def test1(a, *args, **kwargs): print(‘我是中國人.‘) test1(1)
3. 裝飾器的嵌套
<1>. 第一層裝飾器的簡化(outer裝飾器)
<2>. 第二層裝飾器簡化(outer0裝飾器)
<3>. 裝飾器嵌套攻擊額,我們可以發現一層裝飾器其實就是把原函數嵌套進另一個函數中間,因此我們只需要一層一層的剝開嵌套就可以了。
# -*- coding:utf-8 -*- # zhou # 2017/6/17 def outer0(func): def inner(): print(‘Hello, Kitty.‘) ret = func() print(‘我是日本人.‘) return inner def outer(func): def inner(): print(‘你是哪國人?‘) ret = func() print(‘你呢?‘) return inner @outer0 @outer def test1(): print(‘我是中國人.‘) test1() 結果Hello, Kitty. 你是哪國人? 我是中國人. 你呢? 我是日本人.
python系列4