程式扎記: [Python 學習筆記] 函式、類別與模組 : 函式 (lambda 運算式)

標籤

2016年9月6日 星期二

[Python 學習筆記] 函式、類別與模組 : 函式 (lambda 運算式)

轉載自 這裡 
前言 : 
在Python中,函式是一級(First-class)公民,也就是說,在Python中,函式是物件,為 function 的實例. 如果你要定義一個函式,基本上是使用 def 來定義,如同 def 陳述句 中所說明過的,例如你要定義一個最大值的函式 : 
  1. def max(m, n):  
  2.     return m if m > n else n  
  3.   
  4. print(max(103))  # 顯示 10  

lambda 運算式 : 
你可以用 lambda 運算式來定義函式,執行運算式時將會產生函式物件。 例如,上面的 max函式,可以用以下的方式定義 : 


lambda的語法是 : 
lambda arg1, arg2, ....: expression

lambda中arg1、arg2等就相當於定義函式時的參數,之後你可以在expression中使用這些參數。注意!lambda是運算式,不是陳述句,你在 : 之後的也必須是運算式,lambda中也不能有區塊,這表示一些小的運算任務你可以使用lambda,而較複雜的邏輯你可以使用 def 來定義. 

基本上,lambda 會產生 function 的實例,所以在def 陳述句 中所提到的參數定義與引數指定方式,對於lambda所產生的 function 實例都是適用的. 在Python中缺少其它語言中的switch陳述句,以下結合 字典物件 與 lambda 模擬 switch 的示範 : 
- SwitchSim.py : 
  1. score = int(input('Int: '))  
  2. level = score // 10  
  3. {  
  4.     10: lambda: print('Perfect'),  
  5.     9 : lambda: print('A'),  
  6.     8 : lambda: print('B'),  
  7.     7 : lambda: print('C'),  
  8.     6 : lambda: print('D')  
  9. }.get(level, lambda: print('E'))()  
在上例中,字典物件中的值的部份是lambda所建立的函式物件,你使用 get() 方法指定鍵,如果有符合的鍵,就傳回對應的函式物件並執行,否則就傳回 get() 第二個引數所指定的函式並執行,這模擬了switch中default的陳述. 

在Python中,函式是function的實例,所以你可以自由傳遞,將一個函式中所定義的函式傳回也是常見的應用. 例如 : 
- LambdaTest1.py : 
  1. def add(n1):  
  2.     def func(n2):  
  3.         return n1 + n2  
  4.     return func  
  5. print(add(1)(2))  

從一個函式中呼叫另一個函式,這是函式程設中鞣制Curry)的概念。所謂鞣製,是指將接受多個參數的函式,改為接受單一參數的函式,在函式執行過後傳回一個函式物件再套用剩下的參數,就像是將兩個函式鞣製在一起. 

另一個值得注意的是,n1參數的存活期間,本應跟隨著 add() 函式呼叫完成就結束,不過因為n1被綁定在func()函式之中,形成了一個閉包(Closure). 所謂的閉包(Closure),是指一個函式物件(或 函式值)在建立時,綁定了當時作用範圍(Scope)下有效的自由變數(Free variable)。所 以支援閉包的語言,必須有支援一級函式(First-class function),建立函式物件並不等於建立閉包,建立函式物件時同時綁定了某個自由變數,該函式物件才稱之為閉包

在Python中,確實支援閉包的概念. 例如 : 


在上例中,inner() 確實綁定了區域變數x,在 outer() 內部呼叫 inner() 時顯示的是10,而後改變了x為20,由於 inner() 綁定了x,所以傳回的函式執行時,顯示x的值為20. 不過實際上在應用時,還是得小心一點. 例如 : 


在上例中,func() 中的 setX() 宣告的x,其實是 setX() 中的區域變數x,其覆蓋了外部 func() 的x,所以你的n是指定給區域變數x ! 

回到鞣製的討論,實際上其應用,在於先針對既有的資料先行作運算並傳回未運算的函式,待後續資料備妥後再完成整個所需的運算結果。一個例子像是 因 式分解,可以先準備好一定長度的質數表,之後利用該質數表來進行因式分解. 例如 : 
- GCDPNumber.py : 
  1. import math  
  2.   
  3. def prepare_factor(max):  
  4.     prime = [1] * max  
  5.     for i in range(2int(math.sqrt(max))):  
  6.         if prime[i] == 1:  
  7.             for j in range(2*i, max):  
  8.                 if j % i == 0:  
  9.                     prime[j] = 0  
  10.     primes = [i for i in range(2, max) if prime[i] == 1] # 質數表  
  11.   
  12.     def factor(num):  
  13.         list = []  
  14.         i = 0  
  15.         while primes[i] ** 2 <= num:  
  16.             if num % primes[i] == 0:  
  17.                 list.append(primes[i])  
  18.                 num //= primes[i]  
  19.             else:  
  20.                 i += 1  
  21.   
  22.         list.append(num)  
  23.         f = [0] * len(list)  
  24.         for i in range(len(f)):  
  25.             f[i] = list[i]  
  26.         return f  
  27.     return factor  
  28.   
  29. factor = prepare_factor(1000)  
  30. print(factor(100))  
  31. print(factor(200))  
  32. print(factor(977))  
執行結果 : 

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!