明確目的(本章知識點)
- 什麼是高階函數
- 實例-方便理解函數是如何作爲參數或者返回值的
- 函數作爲參數的場景
- 函數作爲返回值的場景
- 函數即作爲參數又作爲返回值的場景
- python內置3個高階函數-map、filter、reduce
模擬教學(嘗試講清楚)
1、什麼是高階函數
- 有一個函數,它的參數是函數
- 有一個函數,它的返回值是函數
- 有一個函數,它的參數和返回值都是函數
- 如上三個函數,都是高階函數。一句話總結就是:(參數是函數)或者(返回值是函數)的函數,就是高階函數。
2、實例-方便理解函數是如何作爲參數或者返回值的
廖雪峯大神寫得非常好,我就直接複製整理過來了。
以Python內置的求絕對值的函數abs()爲例,調用該函數用以下代碼:
>>> abs(-10)
10
但是,如果只寫abs呢?
>>> abs
<built-in function abs>
可見,abs(-10)
是函數調用,而abs
是函數本身。
要獲得函數調用結果,我們可以把結果賦值給變量:
>>> x = abs(-10)
>>> x
10
但是,如果把函數本身賦值給變量呢?
>>> f = abs
>>> f
<built-in function abs>
結論:函數本身也可以賦值給變量,即:變量可以指向函數。
如果一個變量指向了一個函數,那麼,可否通過該變量來調用這個函數?用代碼驗證一下:
>>> f = abs
>>> f(-10)
10
成功!說明變量f現在已經指向了abs函數本身。直接調用abs()函數和調用變量f()完全相同。
3、函數作爲參數的場景
- 先來個簡單的例子理解理解
如下add函數就是高階函數,f就是一個函數
In [156]: def add(x, y, f):
...: return f(x) + f(y)
...:
In [157]: add(-5, 6, abs)
Out[157]: 11
- 實際應用中的場景,比如排序算法
需求:寫一個函數,傳入一個列表。並對列表的值進行排序
例1:實現版本1,先實現最基本的功能,默認是逆序
In [178]: def sort(it):
...: ret = []
...: for x in it:
...: for i, e in enumerate(ret):
...: if x > e:
...: ret.insert(i, x)
...: break
...: else:
...: ret.append(x)
...: return ret
In [179]: sort([1, 2, 34, 6, 8, 5])
Out[179]: [34, 8, 6, 5, 2, 1]
例2:例1中只支持順序排序,如果我要順序排序呢,是否又要重寫一個呢,來個版本2的,當r爲True時就是順序了
In [180]: def sort(it, r=False):
...: ret = []
...: for x in it:
...: for i, e in enumerate(ret):
...: if r:
...: if x < e:
...: ret.insert(i, x)
...: break
...: else:
...: if x > e:
...: ret.insert(i, x)
...: break
...: else:
...: ret.append(x)
...: return ret
In [25]: sort([38, 99, 24, 44, 18])
Out[25]: [99, 44, 38, 24, 18]
In [26]: sort([38, 99, 24, 44, 18], r=True)
Out[26]: [18, 24, 38, 44, 99]
例3:功能上要少寫重複代碼,不然一旦修改則要修改2處,改進版3
In [181]: def sort(it, r=False):
...: ret = []
...: def cmp(a, b):
...: if r:
...: return x < e
...: else:
...: return x > e
...:
...: for x in it:
...: for i, e in enumerate(ret):
...: if cmp(x, e):
...: ret.insert(i, x) # 對比例2,當要修改,本實例只需要修改一次
...: break
...: else:
...: ret.append(x)
...: return ret
例4:使用高階函數來寫該函數,lambda是匿名函數(單行函數)
In [38]: def sort(it, cmp=lambda a, b: a < b):
...: ret = []
...: for x in it:
...: for i, e in enumerate(ret):
...: if cmp(x, e):
...: ret.insert(i, x)
...: break
...: else:
...: ret.append(x)
...: return ret
...:
In [39]: sort([1, 2, 34, 6, 8, 5])
Out[39]: [1, 2, 5, 6, 8, 34]
In [40]: sort([1, 2, 34, 6, 8, 5], lambda a, b: a > b)
Out[40]: [34, 8, 6, 5, 2, 1]
- 部分總結
- 使用高階函數的方式可以少寫很多代碼。也就是說寫代碼可以不用高階函數(會造成代碼量多邏輯複雜)
- 函數作爲參數:通常用於大多數邏輯固定,少部分邏輯不固定的場景。
- python內置了一個排序函數
sorted()
,就是典型的函數作爲參數的函數
4、函數作爲返回值的場景
- 先來個簡單的例子理解理解
In [12]: def build(x, y):
...: def tmp_der(): # 定義一個函數
...: return x * y
...: return tmp_der # return把這個函數作爲結果返回
...:
In [13]: f = build(3, 5) # 把return賦值給了f,return的是一個函數, f的值也是一個函數
In [14]: f # f的值,python一切皆對象,函數也是一個對象
Out[14]: <function __main__.build.<locals>.tmp_der()>
In [15]: f() # 既然是函數那麼就可以調用,f()調用一下就有結果了
Out[15]: 15
-
實際應用中的場景,比如
經驗不夠,編不出來 -
部分總結
函數作爲返回值:通常是用於閉包的場景,需要封裝一些變量
5. 函數即作爲參數又作爲返回值的場景
裝飾器:它的參數是一個函數,返回值也是一個函數。
那麼可以說,所有的裝飾器都是高階函數的一種,理解了裝飾器就理解了此知識點
詳見裝飾器篇
6. python內置3個高階函數-map、filter、reduce
經驗不夠,編不出來
重複回顧(老佔位行)
- 用紙寫出
本章知識點
- 問問自己該知識點有哪些沒理解透徹
- 如果理解透徹就將概念簡化
- 如果不可以,重新
模擬教學
概念簡化(把知識點簡化成一兩句話)
- 什麼是高階函數,爲什麼要用高階函數
(參數是函數)或者(返回值是函數)的函數,就是高階函數。
使用高階函數少些很多代碼,優化業務代碼邏輯。 - 理解函數是如何作爲參數或者返回值
函數fn, 不調用時是一個python函數對象, fn()調用時就是一個函數
- 函數作爲參數的場景
通常用於大多數邏輯固定,少部分邏輯不固定的場景。經驗不夠,編不出來
- 函數作爲返回值的場景
通常是用於閉包的場景,需要封裝一些變量。經驗不夠,編不出來閉包是什麼暫時不知道
- 函數即作爲參數又作爲返回值的場景
裝飾器的時候再深入理解
- python內置3個高階函數-map、filter、reduce
三個函數分別用來做什麼。經驗不夠,編不出來