1. 程式人生 > >Python基礎筆記:函數式編程:高階函數、返回函數、匿名函數、裝飾器、偏函數

Python基礎筆記:函數式編程:高階函數、返回函數、匿名函數、裝飾器、偏函數

iterator 因此 sum() hello 存在 不返回 原因 結構 接受

高階函數

高階函數:一個函數可以接收另一個函數作為參數 或 一個函數可以返回一個函數作為返回值,這種函數稱之為高階函數。

#函數 add 接收 f 函數作為參數
>>> def add(x,y,f):
...     return f(x)+f(y)
...
>>> add(-5,6,abs)
11

可以把匿名函數作為返回值返回

#把匿名函數作為返回值返回
def build(x, y):
    return lambda: x * x + y * y

匿名函數

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

>>> list(map(lambda
x:x*x,list(range(1,10)))) [1, 4, 9, 16, 25, 36, 49, 64, 81] def f(x): return x*x >>> from hello import f >>> list(map(lambda x:x*x,list(range(1,10)))) [1, 4, 9, 16, 25, 36, 49, 64, 81] #這兩種方式等價,不過第一種代碼量更少。
def f(x):
    return x*x

#等價於

lambda x:x*x

返回函數

比如我們實現一個求和函數:

def
calc_sum(*args): ans=0 for i in args: ans+=i return ans

但是如果不需要立刻求和,而是在後面的代碼中,根據需要再計算怎麽辦?

可以不返回求和的結果,而是返回求和的函數:

def lazy_sum(*args):
    def sum():
        ans=0
        for i in args:
            ans+=i
        return ans
    return sum
#調用
>>> L=list(range(1,11)) 
>>> f=lazy_sum(*L) #
返回的函數並沒有立刻執行,而是直到調用了f >>> f() 55

在這個例子中,我們在函數 lazy_sum 中又定義了函數 sum ,並且,內部函數 sum可以引用外部函數 lazy_sum 的參數和局部變量,當lazy_sum返回函數sum時,相關參數和變量都保存在返回的函數中,這種稱為“閉包(Closure)”的程序結構擁有極大的威力。

當我們調用 lazy_sum() 時,每次調用都會返回一個新的函數,即使傳入相同的參數:

>>> f1=lazy_sum(*L)
>>> f2=lazy_sum(*L)
>>> f1==f2
False

一個關於“閉包”的示例:

def count():
    fs=[]
    for i in range(1,4): #每次循環都創建了一個新的函數,然後把創建的3個函數都返回了
        def f():
            return i*i
        fs.append(f)
    return fs
#調用
>>> f1,f2,f3=count() 
>>> f1()
9
>>> f2()
9
>>> f3()
9

怎麽都是9 ?!

原因在於返回的函數引用了變量 i ,但它並非立刻執行。等到三個函數都返回時,它們所引用的變量 i 已經變成了 3,因此最終結果為9......

如果一定要引用循環變量怎麽辦?方法是再創建一個函數,用該函數的參數綁定循環變量當前的值,無論該循環變量後續如何更改,已綁定到函數參數的值不變:

def count():
    fs=[]
    for i in range(1,4):
        def f(i):
            def g():
                return i*i
            return g
        fs.append(f(i))
    return fs
#調用
>>> from hello import count
>>> f1,f2,f3=count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

利用 lambda 函數簡化:

def count():
    fs=[]
    for i in range(1,4):
        def f(i):
            return lambda :i*i
        fs.append(f(i))
    return fs

練習:利用閉包返回一個計數器函數,每次調用它返回遞增整數

def count_num():
    f=[0]
    def count():
        f[0]=f[0]+1
        return f[0]
    return count
>>> from hello import count_num
>>> f=count_num()
>>> f()
1
>>> f()
2
>>> f()
3
>>>

高階函數——map

map() 函數接收兩個參數,一個是函數,一個是Iterable , map將闖入的函數一次作用到序列的每個元素,並把結果作為新的 Iterator 返回

用 map 實現把一個函數 f(x)=x*x ,作用在一個 list 上後的結果輸出:

>>> L=range(1,11)
>>> L=list(range(1,11))
>>> r=map(lambda x:x*x,L)
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

高階函數——reduce

reduce() 函數是接受兩個參數,把一個函數最用在一個序列上,reduce 把結果繼續和序列的下一個元素做累積計算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

用reduce 實現序列求和

>>> from functools import reduce #使用reduce函數需先import
>>> L=list(range(1,11))
>>> reduce(lambda x,y:x+y,L)
55

用reduce 實現把一個整數序列變成整數

>>> L=list(range(1,10))
>>> reduce(lambda x,y:x*10+y,L)
123456789

用reduce + map 實現str 轉換為 int 的函數

>>> def char_num(c):
...     digits={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9}
...     return digits[c]
...
>>> reduce(lambda x,y :x*10+y,list(map(char_num,13654)))
13654

python 有內置的str 與int 互化的函數

>>> str(4515)
4515
>>> int(5252)
5252

練習:利用map()函數,把用戶輸入的不規範的英文名字,變為首字母大寫,其他小寫的規範名字。輸入:[‘adam‘, ‘LISA‘, ‘barT‘],輸出:[‘Adam‘, ‘Lisa‘, ‘Bart‘]

Python基礎筆記:函數式編程:高階函數、返回函數、匿名函數、裝飾器、偏函數