Mark Chang's Blog

Machine Learning, Deep Learning and Python

Python Functional Programming Style 1

今天來看看如何用python的Functional Programming tool來簡化程式碼

所謂的Functional Programming, 是指像是Lisp或Haskell這樣的程式語言

python所提供的Functional Programming tool

可以用Functional Programming這些語言的風格來寫python

1. lambda

lambda這個詞是來自於Lambda Calculus

簡而言之, Lambda Calculus是一種計算理論

若想了解Lambda Calculus是什麼, 請看:http://en.wikipedia.org/wiki/Lambda_calculus

lambda 這個key word在python裡面是用來定義anonymous functions或small function

例如:

1
2
3
>>> my_function = lambda x : x+2
>>> print my_function(1)
3

或:

1
2
>>> print (lambda x : x+2 ) (1)
3

2. map

假設有一個function和一個list,如下:

1
2
>>> my_function = lambda x : x+3
>>> my_list = [1,2,3,4,5]

如果要把 my_list 中的每個element用 my_function 做運算

例如:

1
2
3
4
5
6
>>> my_list_2 = []
>>> for x in my_list:
...     my_list_2.append(my_function(x))

>>> print my_list_2
[4, 5, 6, 7, 8]

這可以用map改成這樣:

1
2
3
>>> my_list_2 = map(my_function,my_list)
>>> print my_list_2
[4, 5, 6, 7, 8]

也可以直接這樣寫

1
2
3
>>> my_list_2 = map(lambda x : x+3,[1,2,3,4,5])
>>> print my_list_2
[4, 5, 6, 7, 8]

這樣都可以把for迴圈化簡掉

map也可以用於多個argument的function

例如:

1
2
>>> print map(lambda x,y : x*y ,[1,2,3,4], [2,4,6,8])
[2, 8, 18, 32]

3.filter

給定一個list如下

1
>>> my_list = [1,2,3,4,5,6,7,8]

假如要取出 my_list 中為偶數的數字,如下:

1
2
3
4
5
6
7
>>> my_list_2 = []
>>> for x in my_list:
...     if x%2 == 0:
...             my_list_2.append(x)

>>> print my_list_2
[2, 4, 6, 8]

filter的概念就是去掉function運算後為False的element,如下:

1
2
3
>>> my_list_2 = filter(lambda x : x%2 == 0, my_list)
>>> print my_list_2
[2, 4, 6, 8]

這樣就可以省略掉for和if,把成式碼合併到一行之中

再一例子,如果要把 my_list 中偶數的element取出來後平方,可以這樣寫:

1
2
3
>>> my_list_2 = filter(lambda x : x**2 if x%2==0 else False, my_list)
>>> print my_list_2
[2, 4, 6, 8]

4.reduce

給定一個list如下

1
>>> my_list = [3,2,1,6,5,4]

如果要算出這個例子的總和,用for迴圈會這樣寫

1
2
3
4
5
6
>>> sum=0
>>> for x in my_list:
...     sum+=x

>>> print sum
21

這樣至少要寫三行,如果用reduce的話一行就夠了

1
2
3
>>> sum = reduce(lambda a,b:a+b,my_list)
>>> print sum
21

reduce的概念如下,用這個function把list中前兩個合併成一個

一直這樣合併下去

以下是reduce的分解過程

把程式碼複製後貼到 my_reduce.py 檔案

my_reduce.py
1
2
3
4
5
6
7
8
9
10
def my_reduce(my_fun,my_list):
      print my_list
      if len(my_list) == 1:
              return my_list[0]
      elif len(my_list) >= 2:
              my_list_1 = my_fun(my_list[0], my_list[1])
              return my_reduce(my_fun, [my_list_1] + my_list[2:])
      else:
      		    print "Error: reduce of empty sequence"
              return False

到interactive mode 執行看看

1
2
3
4
5
6
7
8
9
>>> from my_reduce import *
>>> my_reduce(lambda a,b:a+b,my_list)
[3, 2, 1, 6, 5, 4]
[5, 1, 6, 5, 4]
[6, 6, 5, 4]
[12, 5, 4]
[17, 4]
[21]
21

看到了list前面兩個被function合併成一個,這樣繼續合併下去,得出結果

再舉一例,

如果要求出my_list中的最大值, 可以這樣:

1
2
3
>>> max = reduce(lambda a,b: a if a>=b else b, my_list)
>>> print max
6

分解過程如下:

1
2
3
4
5
6
7
8
>>> my_reduce(lambda a,b: a if a>=b else b,my_list)
[3, 2, 1, 6, 5, 4]
[3, 1, 6, 5, 4]
[3, 6, 5, 4]
[6, 5, 4]
[6, 4]
[6]
6

5.Further reading:

想要看更多關於lambda,map,filter和reduce的用法,請到:

http://www.python-course.eu/lambda.php

http://docs.python.org/2/tutorial/datastructures.html#functional-programming-tools

Comments