詳談Python的高級特性、函數式編程、高階函數

1、什麼是Python的高級特性?

這個問題對於許多正在學習Python的小夥伴來說可能會很疑惑?很多人知道這個名詞,但不知道這玩意到底是什麼。其實,Python作爲一門高級語言它有許多的內置函數,運用這些函數可以很方便的完成一些功能,而這些特性,籠統的可稱爲Python的高級特性。簡單地說Python的高級特性就是一些Python函數的高級用法。

(1)集合的推導式

  • 列表推導式,使用一句表達式構造一個新列表,可包含過濾、轉換等操作。

a = [i for i in range(100) if i % 2 == 0]  #100以內所有偶數的列表
  • 字典推導式,使用一句表達式構造一個新列表,可包含過濾、轉換等操作。

b = {key: value for key, value in enumerate(reversed(range(100)))}
  • 集合推導式

d = {i for i in range(100)}

3、函數式編程

  • 函數本身可以賦值給變量,賦值後變量爲函數;
  • 允許將函數本身作爲參數傳入另一個函數;
  • 允許返回一個函數。

函數式編程的特點

  • 把計算視爲函數而非指令
  • 純函數式編程,不需要變量
  • 支持高階函數,代碼簡潔

python支持的函數式編程

  • 不是純函數式編碼:允許有變量
  • 支持高階函數:函數也可以作爲變量傳入
  • 支持閉包:有了閉包就能返回函數
  • 有限度地支持匿名函數

2、高階函數

  • 變量可以是指向函數

  • 函數的參數可以接收變量

  • 一個函數可以接收另一個函數作爲參數

  • 能接收函數作爲參數的函數就是高階函數

#函數作爲參數示例
def add(x,y,f):
  return f(x)+f(y)
add(-5,9,abs)    #abs()求絕對值

 

根據函數的定義,函數執行的代碼實際上是:

abs(-5) + abs(9)

由於參數 x, y 和 f 都可以任意傳入,如果 f 傳入其他函數,就可以得到不同的返回值。

(1)map函數

map()是 Python 內置的高階函數,它接收一個函數 f 和一個 list,並通過把函數 f 依次作用在 list 的每個元素上,得到一個新的 list 並返回。

def f(x):
    return x*x
print (map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]))

如:使用map()函數將函數f(x)和list傳入,就會對list的每個值計算平方,返回結果:[1, 4, 9, 10, 25, 36, 49, 64, 81]

注意:map()函數不改變原有的 list,而是返回一個新的 list。

  利用map()函數,可以把一個 list 轉換爲另一個 list,只需要傳入轉換函數。

由於list包含的元素可以是任何類型,因此,map() 不僅僅可以處理只包含數值的 list,事實上它可以處理包含任意類型的 list,只要傳入的函數f()可以處理這種數據類型.

(2)reduce函數

reduce()函數也是Python內置的一個高階函數。reduce()函數接收的參數和 map()類似,一個函數 f,一個list,但行爲和 map()不同,reduce()傳入的函數 f 必須接收兩個參數,reduce()對list的每個元素反覆調用函數f,並返回最終結果值。

例如,編寫一個f函數,接收x和y,返回x和y的和:

def f(x, y):
    return x + y

調用 reduce(f, [1, 3, 5, 7, 9])時,reduce函數將做如下計算:

先計算頭兩個元素:f(1, 3),結果爲4;
再把結果和第3個元素計算:f(4, 5),結果爲9;
再把結果和第4個元素計算:f(9, 7),結果爲16;
再把結果和第5個元素計算:f(16, 9),結果爲25;
由於沒有更多的元素了,計算結束,返回結果25。

上述計算實際上是對 list 的所有元素求和。雖然Python內置了求和函數sum(),但是,利用reduce()求和也很簡單。

reduce()還可以接收第3個可選參數,作爲計算的初始值。如果把初始值設爲100,計算:

reduce(f, [1, 3, 5, 7, 9], 100)

結果將變爲125,因爲第一輪計算是:

計算初始值和第一個元素:f(100, 1),結果爲101。

注意:在python3.x後的版本中,reduce函數被劃歸到的functools庫,因此使用reduce函數之前必須先引入functools庫

(3)filter()函數

 filter()函數是 Python 內置的另一個有用的高階函數,filter()函數接收一個函數 f 和一個list,這個函數 f 的作用是對每個元素進行判斷,返回 True或 False,filter()根據判斷結果自動過濾掉不符合條件的元素,返回由符合條件元素組成的新list。

例如,要從一個list [1, 4, 6, 7, 9, 12, 17]中刪除偶數,保留奇數,首先,要編寫一個判斷奇數的函數:

def is_odd(x): 
    return x % 2 == 1

然後,利用filter()過濾掉偶數:

filter(is_odd, [1, 4, 6, 7, 9, 12, 17])

結果:[1, 7, 9, 17]

利用filter(),可以完成很多有用的功能,例如,刪除 None 或者空字符串:

def is_not_empty(s): 
    return s and len(s.strip()) > 0 
filter(is_not_empty, ['test', None, '', 'str', ' ', 'END'])

結果:['test', 'str', 'END']

注意: s.strip(rm) 刪除 s 字符串中開頭、結尾處的 rm 序列的字符

閉包

內層函數引用了外層函數的變量(參數也算變量),然後返回內層函數,這種情況稱之爲閉包。如果在一個內部函數裏,對在外部作用域(但不是在全局作用域)的變量進行引用,那麼內部函數就被認爲是閉包

閉包的特點是返回的函數還引用了外層函數的局部變量,所以,要正確使用閉包,就要確保引用的局部變量在函數返回後不能變。

你可能認爲調用f1(),f2()和f3()結果應該是1,4,9,但實際結果全部都是 9(請自己動手驗證)。

原因就是當count()函數返回了3個函數時,這3個函數所引用的變量 i 的值已經變成了3。由於f1、f2、f3並沒有被調用,所以,此時他們並未計算 i*i,當 f1 被調用時才計算i*i.

因此,返回函數不要引用任何循環變量,或者後續會發生變化的變量。

裝飾器

python裝飾器就是用於拓展原來函數功能的一種函數,這個函數的特殊之處在於它的返回值也是一個函數,使用python裝飾器的好處就是在不用更改原函數的代碼前提下給函數增加新的功能。

通過高階函數返回新函數,通過接收一個函數,內部對其包裝,然後返回一個新函數,這樣子動態的增強函數功能。

通過高階函數傳遞函數參數,新函數添加舊函數的需求,然後執行舊函數。

裝飾器作用:可以極大簡化代碼,避免每個函數編寫重複性的代碼

(1)、打印日誌:@log    (2)、檢測性能:@performance

(3)、數據庫事務:@transaction   (4)、URL路由:@post('/register')

定義裝飾器函數三步走:

 (1)、定義自己先要執行的函數

(2)

(3)、裝飾器進行修飾

匿名函數

高階函數可以接收函數做參數,有些時候,我們不需要顯式地定義函數,直接傳入匿名函數更方便。

在Python中,對匿名函數提供了有限支持。還是以map()函數爲例,計算 f(x)=x2 時,除了定義一個f(x)的函數外,還可以直接傳入匿名函數:

map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])

[1, 4, 9, 16, 25, 36, 49, 64, 81]

通過對比可以看出,匿名函數 lambda x: x * x 實際上就是:

def f(x):

    return x * x

關鍵字lambda 表示匿名函數,冒號前面的 x 表示函數參數。

匿名函數有個限制,就是隻能有一個表達式,不寫return,返回值就是該表達式的結果。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章