首頁  >  文章  >  後端開發  >  Python入門學習之函數式程式設計

Python入門學習之函數式程式設計

黄舟
黄舟原創
2016-12-16 16:36:371035瀏覽

一 前言

  初次接觸函數式程式設計是在學習分散式計算的時候,那時候對map/reduce是不明覺厲,也沒懂多少原理方面的東西。 Python中的函數式程式設計也算是初步了解map/reduce。所謂函數式編程,本質上是可以歸結為過程導向的程序設計,但是它的思想很接近數學計算。它比一般的程式設計範式更抽象,而且純粹的函數式程式語言所寫的函數是沒有變數的,只要確定了輸入,那也就確定了輸出。它的另一個特點就是把函數本身當作參數傳入到另一個函數中,允許傳回一個函數。

 

二 高階函數(High-order Function)

  在Python中,函數名稱本質上也是一個變數。我們可以將一個函數名賦值給一個變量,再透過這個變數來呼叫函數。在使用python以過程為導向的程式設計中,一個有變數的函數是很普遍的設計,但是如果這個變數是一個函數,那麼這個有變數的函數我們就稱之為高階函數了。

  一個簡單的高階函數範例:

def fun(n):
   return n+1

def highorder(x, y, f):
   return fx)+定義的highorder就是一個高階函數,它是一個可以在參數中接收其他函數的函數。

 

三 Map/Reduce

  有了上面的高階函數基礎,現在再來理解Map/Reduce就很容易了。 Map函數接收兩個參數,一個是函數,另一個是Iterable。 Map將函數依序作用在Iterable的每一個元素上,並將結果傳回為新的Iterator。

  看下面的例子:

def fun(n):

   return n*2

m=map(fun, [1,2,3,4,5])PRint(m)
m=map(fun, [1,2,3,4,5])PRint(m)
python hello_python.py
[2, 4, 6, 8, 10]


   map把函數fun依次作用在列表的每一個元素上,就得到了[2,4,6,8,10]。

  如果嫌定義一個fun函數比較麻煩,可以使用lambda來進行簡化,如下:

m=map(lambda n:n*2, [1,2,3,4,5])

    Reduce的用法。 Reduce同Map一樣,也是將一個函數依序作用在一個序列上,但是要求這個函數必須接收兩個函數。 Reduce再把函數作用在前兩個參數的結果與下一個序列的元素上。

  下面就用Reduce來實現一個序列求和運算,見下例:

def add(x,y):

   return x+y

r=reduce(add, [1,2,3,4,4,2,2,3,4, [1,2,3,4, 1,2,3,4, [1,2,3,4,2 5])

print(r)


E:Studypython>python hello_python.py
15


   它的lambda版本為:

r=reduce(lambda x,1,120,00 ,4,5])

 

四回傳函數

  在前面就已經表述過函數是可以被賦值給一個變數的,那麼既然函數可以回傳一個變數,當然也是可以傳回一個函數的。別看返回變數和返回函數本質上差別不大,但是這種返回函數的機制卻在應用上有著極大的作用。

  請看下面的範例:

def wrapper(*param):

   def calc():

       x

       return sum            

   return calc;


f= wrapper(1,2,3,4,5)

print(f())

E:Studypython>python hello_python.py
15


  wr在呼叫此函數後,其會傳回一個內部定義的函數,而這個函數要在真正呼叫它時才會執行。另外也要注意的是,calc函式中存取的資料是由wrapper帶進來的,而這些參數會與calc被保存在一起,我們稱之為「閉包」(closure)。

 

五 閉包(Closure)

  初次接觸閉包,對其並不是十分的理解。仍以四中的程式碼作為範例。

  wrapper是一個函數,包含不定數的參數param。比較特殊的地方是這個函數體中也定義了一個新的函式calc,這個新函式的函式體內正引用了一個外在函式wrapper的參數,也就是說,外在函式傳遞過來的參數已經和calc函式綁定到了一起,形成了一個新函數。我們可以把param看成是這個新函數的一個設定資訊。配置資訊如果不一樣,函數的輸出當然也就不一樣了。

  為了更好的理解閉包,看以下代碼示例:

def wrapper(conf):

   def calc(n):

       return conf+n

   return calc

f1=wrapper(1)

f2=wrapper (2)


print(f1(100))
print(f2(100))

E:Studypython>python hello_python.py
101
102

   分析上述程式碼,呼叫wrapper(1)時會回傳一個函數,而這個函數的配置資訊是conf的值為1。再呼叫wrapper(2)時會傳回另外一個函數,而這個函數的設定資訊是conf的值為2。所以在隨後的我們都傳入100參數來呼叫f1和f2時得到的結果為101和102,其根本原因就在於兩個函數的配置資訊不一樣。

  值得我們注意的是,並不是外部函數的所有信息都會被內部函數做為配置信息,只有外部函數的參數才會被內部函數作為配置信息。至於外部函數的局部變量,就不會被做為配置資訊了。

    

六 裝飾器(Decorator)

  發明Decorator的初衷是為了解決在不修改原有函數程式碼的情況下,在函數呼叫前後就增加其他功能,例如列印等。 Decorator基本上就是一個回傳函數的高階函數,請看下面這個列印日誌的decorator,程式碼如下:

def decorator(func):
   def wrapper():
      print("Before invok:"  
       print("After invoked:")
   return wrapper        

def func():
 

E:Studypython>python hello_python. py
Before invoked:
Func invoked:
After invoked:


   上述程式碼為func定義了一個裝飾器,在呼叫這個裝飾器時傳回一個函數,在這個函數中加上需要的程式碼後再用func。但這裡有一個問題,就是原來可以直接呼叫func,現在卻要呼叫f了。要解決這個問題很容易,因為在python中函數是可以賦值給一個變數的,只需要將f改成func就可以了。如下圖所示:

func=decorator(func)
func()

   python中為實作這個機制提供了一個語法:@。在func前加上@decorator即可,相當於執行了func=decorator(func),這樣就解決了使用相同的名字來呼叫增加功能後的程式碼。如下圖所示:


def decorator(func):
   def wrapper():

       print("Before invoked:")

     5("Before invoked:")

     return wrapper        


@decorator
def func ():
   print("Func invoked:")
 
func()


   另外還有如何為decorator增加參數以及如何修改wrapper的__name__屬性為func的內容,這裡就不講述了。

 

七 偏函數(Partial Function)

  何謂偏函數?偏函數就是給函數增加預設參數後的函數。在python中,可以使用functools.partial來產生一個函數的偏函數。拿python中的int()做範例,int()函數預設是以十進位轉換,如果想產生一個以8進位轉換的偏函數,可以如下實作:

print(int('12345'))

int8=functools.partial(int, base=8)

print(int8('12345'))

 

式八總結

  在這篇文章中,主要講述了函數式程式設計中的幾個基本概念。個人感覺最難理解的就是Decorator了,特別是其中的所謂配置資訊。如有錯誤之處,敬請留言! ! !

 以上就是Python入門學習之函數式程式設計的內容,更多相關文章請關注PHP中文網(www.php.cn)! 

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn