Python學習(13)--Lambda表示式和switch語句的實現

weixin_34026276發表於2018-03-21

Python學習(13)--Lambda表示式和switch語句的實現

1.Lambda表示式定義匿名函式

         在Python中,Lambda表示式是用來快速定義一個最小函式,這個函式小到什麼程度呢,小到只有一行程式碼,一條語句,在Python中有時候我們為了提高程式的可讀性,或者一個功能塊小到我們並不需要定義一個函式來實現它的時候就用到了Lambda表示式,那麼什麼又是Lambda表示式呢?下面我們通過一個程式碼例子來了解下:

[python] view plain copy

  1. def f(x,y):
  2.     return x*y
  3. g=lambda x,y:x*y
  4. print(g(2,3))

如上所示,開始我們定義了一個常見的函式f(x,y),這個函式的功能很簡單,就是返回兩個形式引數x和y的乘積,函式的名字為f。lambda x,y:x*y一句就定義了一個極簡的函式,這個函式是匿名的,引數列表為x和y,返回值就是x*y,不需要特定的return語句返回,lambda表示式返回的是一個函式物件,這個函式物件我們用g來接收它,當呼叫這個函式時,也是用g這個函式物件來呼叫,如g(2,3)就是呼叫lambda表示式返回的函式。以下是對一個lambda表示式各個部分的詳細註解.

      
       Lambda表示式更加精簡,有時候我們可能並不需要呼叫一個函式模組很多次,或者這個函式的命名並不容易,而這個函式模組又特別簡單,簡單到只需要一條語句,這個時候我們就可以使用lambda表示式構造一個匿名函式物件,lambda表示式返回的也是一個函式物件,可以看到程式碼如下:

[python] view plain copy

  1. g=lambda x,y:x*y;
  2. print(g)

如上我們通過lambda表示式構造了一個匿名函式物件並列印它,列印結果如下:

       
       通過列印結果可以看到,function指的是這是一個函式,是通過lambda表示式構造出來的,後面是這個函式物件所在的記憶體地址。
2.lambda表示式應用案例
  接下來我們舉一個例子,來更好的來了解lambda表示式。比如一個程式例子求整數n的階乘,我們先來了解下之前慣用的方法,使用遞迴函式的這種方法程式碼如下:

[python] view plain copy

  1. def f(n):
  2.     if n==0:
  3.         return 1
  4.     else:
  5.         return n*f(n-1)
  6. print(f(5))

程式碼的列印結果如下:

   
其實遞迴的過程就是一個先入棧,後出棧的過程,棧這種資料結構的特點就是先進後出,我們可以看下面這個圖來了解這種遞迴過程,圖解如下:
   
   如上圖所示,fun(5)=5*fun(4),但是這個時候並不知道fun(4)是多少,fun(5)先入棧,fun(4)呼叫函式,fun(4)=4*fun(3),這個時候需要求fun(3),fun(3)先入棧,fun(3)=3*fun(2),又要求fun(2),fun(2)入棧,fun(2)=2*fun(1),fun(1)=1*fun(0),緊接著fun(1),fun(0)依次入棧,此時從棧底到棧頂依次是fun(5),fun(4),fun(3),fun(2),fun(1),fun(0).
   當n=0時,fun(0)=1,fun(0)出棧;fun(1)=1*fun(0),fun(1)=1,fun(1)出棧;fun(2)=2*fun(1),fun(2)=2,fun(2)出棧;fun(3)=3*fun(2),fun(3)=6,fun(3)出棧;fun(4)=4*fun(3),fun(4)=24,fun(4)出棧;fun(5)=5*fun(4),fun(5)=120,fun(5)
出棧。最後fun(5)=120,打完收工。出棧次序為fun(0),fun(1),fun(2),fun(3),fun(4),fun(5)。
   這種不斷的遞迴呼叫有兩個缺點,一是需要不斷入棧出棧,很是耗費記憶體,而且即使現在的記憶體優化機制有多麼的好,如果讓程式設計師去編寫程式碼遞迴呼叫函式也是很耗腦力的。
   下面我們用lambda表示式來解決這個n的階乘問題,程式碼如下:

[python] view plain copy

  1. from functools import reduce
  2. l={1,2,3,4,5}
  3. f=lambda x,y:x*y
  4. result=reduce(f,l)
  5. print(result)

程式碼的執行結果與上圖是一樣的,我們主要講解下lambda表示式起到的作用與reduce函式的功能.

   首先我們定義一個序列l,其中l其實就是求n的階乘需要用到的數,這裡我們拿5的階乘來舉例,f是lambda表示式返回的函式物件,這個函式有兩個引數x和y,函式的返回值就是x和y的乘積。
   然後,我們使用一個叫做reduce的函式,這個函式的功能就是,把序列l中的值依次取出來,作為f的實參並呼叫函式f,期間函式f的返回結果,也會作為實參與序列l的元素一起作為實參,呼叫函式f,最後直到l的元素全部用完,這麼說可能不好理解,沒關係,我們用下面的詳細步驟可以很清楚的瞭解整個過程.如下:
  (1)l前2個元素作為實參,呼叫f,f(1,2)=2,返回結果2
  (2)返回結果2與l中的第3個元素作為實參,呼叫f,f(2,3)=6,返回6
  (3)返回結果6與l中的第4個元素作為實參,呼叫f,f(6,4)=24,返回24
  (4)返回結果24與l中的第5個元素作為實參,呼叫f,f(24,5)=120,返回120
  (5)最後l中沒有元素,最終返回結果120,result=120,結束
  可以看到,在求n得階乘過程中,我們把其中最簡單的乘操作抽調出來,並用lambda來實現這個簡單的操作,其他具體如何乘的過程,我們都交給了Python中預定義的函式reduce,程式設計簡單可行,可讀性強,可以說比起遞迴節省了不少腦力。
3.Switch語句的實現
      相信大家在學習C語言時都學過switch語句,不過Python中並沒有switch語句,使用switch語句,需要用字典來實現它的結構,試想一下如果我們在程式設計時不使用switch語句,就只能使用if...elif...else這種判斷結構來進行判斷篩選,直到條件符合,執行需要執行的程式碼塊,下面我們使用這種if...elif...else結構來實現switch結構,程式碼如下:

[python] view plain copy

  1. def add(x,y):
  2.     return x+y
  3. def subtract(x,y):
  4.     return x-y
  5. def mul(x,y):
  6.     return x*y
  7. def divide(x,y):
  8.     return x/y
  9. def operator(o,x,y):
  10.     if o=='+':
  11.         print(add(x,y))
  12.     elif o=='-':
  13.         print(subtract(x,y))
  14.     elif o=='*':
  15.         print(mul(x,y))
  16.     elif o=='/':
  17.         print(divide(x,y))
  18.     else:
  19.         pass
  20. operator('/'52)

如上程式碼所示,我們實現了一個簡單的計算器程式,程式的主要功能是計算兩個數的加減乘除運算,4個函式add(x,y),subtract(x,y),mul(x,y),divide(x,y)分別實現加減乘除運算,函式operator(o,x,y)是使用if...elif...else結構實現switch語句,通過多級判斷使用者運算子,呼叫相應的函式,實現簡單的計算器功能.

    最後,operator('/',5,2),呼叫計算器程式,實現5/2。列印結果如下:
    
       這種判斷結構實現switch語句雖然可行,但是其缺點也不可避免.主要有兩點,一是程式碼看起來並不簡潔明瞭,結構混亂,可讀性也比較差;二是程式可能需要進行多次判斷,才能確定相應運算操作,比如operator('/',5,2),需要進行4次判斷才能確定呼叫函式divide(x,y),這種判斷結構是很耗費記憶體的。
      下面我們來使用字典來實現switch語句。字典元素都是鍵值對,那麼如何確定字典元素的鍵和值呢?先看如下程式碼:

[python] view plain copy

  1. def add(x,y):
  2.     return x+y
  3. def subtract(x,y):
  4.     return x-y
  5. def mul(x,y):
  6.     return x*y
  7. def divide(x,y):
  8.     return x/y
  9. print(add)
  10. print(subtract)
  11. print(mul)
  12. print(divide)

程式碼執行結果如下:

        
       可以看出,列印每個函式名,結果列印出的是一個個的函式物件,function代表一個函式,後面是函式名,以及這個函式物件在記憶體中的地址,為什麼說是一個個函式物件呢?因為通過列印結果可以看出其在記憶體空間中的地址,既然記憶體為他分配了空間,說明他是記憶體中的例項,即物件。
       既然我們通過函式名可以得到函式物件,那我們用字典實現switch語句,初始化字典的鍵值對可以這樣編寫程式碼,程式碼如下:

[python] view plain copy

  1. operator={'+':add,'-':subtract,'/':divide,'*':mul}
  2. print(operator['+'](5,2))
  3. print(add(5,2))

如上程式碼所示,我們初始化字典時,把運算子作為字典的鍵,而函式物件作為字典的值,這樣我們就可以通過字典的鍵,也就是運算子,獲取到相應的函式物件,並呼叫這個函式物件,比如operator['+'],我們獲取到了函式物件add,即operator['+']==add,而通過函式物件呼叫函式時,add(5,2)與operator['+'](5,2)是等價的,列印結果如下:

       
       在瞭解了字典在實現switch語句時如何初始化字典,下面我們就完完整整的實現這個計算器程式,程式碼如下:

[python] view plain copy

  1. def add(x,y):
  2.     return x+y
  3. def subtract(x,y):
  4.     return x-y
  5. def mul(x,y):
  6.     return x*y
  7. def divide(x,y):
  8.     return x/y
  9. operator={'+':add,'-':subtract,'/':divide,'*':mul}
  10. def fun(o,x,y):
  11.     print(operator.get(o)(x,y))
  12. fun("/",5,2)

我們定義了一個函式fun(o,x,y),形參o為運算子,x和y為運算元,operator.get(o)(x,y),就是通過運算子獲取字典裡初始化好的函式物件,並呼叫函式實現運算,這樣就實現了switch語句,避免了之前if...elif...else結構需要多重判斷耗費記憶體的問題,真正實現一步到位,並且把資料部分與運算部分分割開來,程式碼的可讀性更強。

       程式碼的執行結果如下:
       
 
      最後,大家看我的部落格可能會覺得有些地方說的過分的細,甚至有些囉嗦,其實我的本意是在前期我們一同把Python的基礎打好,這樣以後我們學習一些框架就會得心應手,比如TensorFlow和caffe這些資料分析和處理的框架。其實無論學習Python或者這些框架,我們最終的目的都是要實現演算法的思想,比如機器學習演算法或者深度學習模型,"工欲善其事必先利其器",打好這些程式設計基礎可以讓我們在後面學習演算法時,只注重演算法本身的思想,而不用再把精力耗費在程式設計上,畢竟仰望星空前需要腳踏實地。
      下一節,我們將會介紹內建函式,敬請期待。

相關文章