1. 程式人生 > >Python匿名函數詳解

Python匿名函數詳解

abcd highlight pack ces iss 無需 最好 pri 必須

轉載自傑瑞的專欄

lambda這個名稱來自於LISP,而LISP則是從lambda calculus(一種符號邏輯形式)取這個名稱的。在Python中,

lambda作為一個關鍵字,作為引入表達式的語法。想比較def函數,lambda是單一的表達式,而不是語句塊!

你僅能夠在lambda中封裝有限的業務邏輯,這樣設計的目的:讓lambda純粹為了編寫簡單的函數而設計,def則

專註於處理更大的業務。

在編程語言中,函數的應用:

1. 代碼塊重復,這時候必須考慮用到函數,降低程序的冗余度

2. 代碼塊復雜,這時候可以考慮用到函數,降低程序的可讀性

在python,有兩種函數,一種是def定義,一種是lambda函數(一種生成函數對象的表達式形式,因為她和LISP語言很相似,所以取名字為lambda函數)

#假如要求兩個數之和,用普通函數或匿名函數如下:

1. def func(x,y):return x+y

2. lambda x,y: x+y

在編程語言中,C/C++/Java屬於過程式編程,而匿名函數(lambda)一般應用於函數式編程中,舉個簡單例子也許比較好理解,對於一個列表,要求大於3的元素.

過程式編程實現: 也就是常規的方法

  1. >>> L1 = [1,2,3,4,5]
  2. >>> L2 = []
  3. >>> for i in L1:
  4. if i>3:
  5. L2.append(i)
  6. >>> L2
  7. [4, 5]

函數式編程實現: 運用filter,給其一個判斷條件即可

>>> def func(x): return x>3 #在函數中
>>> filter(func,[1,2,3,4,5])
[4, 5]

如果運用匿名函數,則更加精簡,一行就可以了:

>>> filter(lambda x:x>3,[1,2,3,4,5])
[4, 5]

總結: 從中可以看出,lambda一般應用於函數式編程,代碼簡潔,常和reduce,filter等函數結合使用。

格式如下:

lambda argument1
, argument2,... argumentN :expression using arguments

解構上面的例子

x 為lambda函數的一個參數

分割符

x>3 則是返回值,在lambda函數中不能有return,其實:後面就是返回值

為什麽要用匿名函數?

1. 程序一次行使用,所以不需要定義函數名,節省內存中變量定義空間

2. 如果想讓程序更加簡潔時。

匿名函數幾個規則:

1. 一般也就一行表達式,必須有返回值

2. 不能有return

3. 可以沒有參數,可以有一個或多個參數

>>> def func(x): x+y
>>> func
<function func at 0x0000000002F48DD8>
>>> lambda x: x+y
<function <lambda> at 0x0000000002F48D68>

無參匿名函數:

------

>>> t = lambda : True #分號前無任何參數
>>> t()
True

等價於下面的def定義的函數
>>> def func(): return True
>>> func()
True

------

>>> s = "this is\na\ttest" #建此字符串按照正常情形輸出
>>> s
‘this is\na\ttest‘
>>> print s.split() #split函數默認分割:空格,換行符,TAB
[‘this‘, ‘is‘, ‘a‘, ‘test‘]
>>> ‘ ‘.join(s.split()) #用join函數轉一個列表為字符串
‘this is a test‘

等價於

>>> (lambda s:‘ ‘.join(s.split()))("this is\na\ttest")
帶參數匿名函數

>>> lambda x: x**3 #一個參數
>>> lambda x,y,z:x+y+z #多個參數
>>> lambda x,y=3: x*y #允許參數存在默認值

匿名函數調用

#直接賦值給一個變量,然後再像一般函數調用

------

>>> c = lambda x,y,z: x*y*z
>>> c(2,3,4)
24

------

>>> c = lambda x,y=2: x+y #使用了默認值
>>> c(10) #不輸的話,使用默認值2
12

------

>>> a = lambda *z:z #*z返回的是一個元祖
>>> a(‘Testing1‘,‘Testing2‘)
(‘Testing1‘, ‘Testing2‘)

------

>>> c = lambda **Arg: Arg #arg返回的是一個字典
>>> c()
{}

#直接後面傳遞實參

------

>>> (lambda x,y: x if x> y else y)(101,102)
102

------

>>> (lambda x:x**2)(3)
9

#lambda返回的值,結合map,filter,reduce使用

>>> filter(lambda x:x%3==0,[1,2,3,4,5,6])
[3, 6]

等價於下面的列表推導式

>>> l = [x for x in [1,2,3,4,5,6] if x%3==0]
>>> l
[3, 6]

嵌套使用

#lambda嵌套到普通函數中,lambda函數本身做為return的值

------

>>> def increment(n):
... return lambda x: x+n
...
>>> f=increment(4)
>>> f(2)
6

------

>>> def say():
... title = ‘Sir,‘
... action= lambda x: title + x
... return action
...
>>> act = say()
>>> act(‘Smith!‘)
‘Sir,Smith!‘

大量例子:

  • 例01: 字符串聯合,有默認值,也可以x=(lambda...)這種格式

>>> x = (lambda x="Boo",y="Too",z="Zoo": x+y+z)
>>> x("Foo")
‘FooTooZoo‘

  • 例02: 和列表聯合使用

>>> L = [lambda x:x**2,\
lambda x:x**3,\
lambda x:x**4]

>>> for f in L:
... print f(2)
...
4
8
16

也可以如下面這樣調用

>>> print L[0](3)
9

  • 例03: 和字典結合使用

>>> key = ‘B‘
>>> dic = { ‘A‘: lambda: 2*2,\
... ‘B‘: lambda: 2*4,\
... ‘C‘: lambda: 2*8}
>>> dic[key]()
8

  • 例04: 求最小值

>>> lower = lambda x,y: x if x<y else y
>>> lower(‘aa‘,‘ab‘)
‘aa‘

  • 例05: 和map及list聯合使用

>>> import sys
>>> showall = lambda x:list(map(sys.stdout.write,x))
>>> showall([‘Jerry\n‘,‘Sherry\n‘,‘Alice\n‘])
Jerry
Sherry
Alice

>>> showall([‘Jerry‘,‘Sherry‘,‘Alice‘])
JerrySherryAlice

等價於下面

>>> showall = lambda x: [sys.stdout.write(line) for line in x]
>>> showall((‘I\t‘,‘Love\t‘,‘You!‘))
I Love You![None, None, None]

  • 例06: 在Tkinter中定義內聯的callback函數

import sys
from Tkinter import Button,mainloop

x = Button(text=‘Press me‘,
command=(lambda:sys.stdout.write(‘Hello,World\n‘)))
x.pack()
x.mainloop()

技術分享

>>>

Hello,World!

Hello,World!

  • 例07: lambda和map聯合使用

>>> out = lambda *x: sys.stdout.write(‘ ‘.join(map(str,x)))
>>> out(‘This‘,‘is‘,‘a‘,‘book!\n‘)
This is a book!

  • 例08: 判斷字符串是否以某個字母開頭

>>> print (lambda x: x.startswith(‘B‘))(‘Bob‘)
True

-----

>>> Names = [‘Anne‘, ‘Amy‘, ‘Bob‘, ‘David‘, ‘Carrie‘, ‘Barbara‘, ‘Zach‘]
>>> B_Name= filter(lambda x: x.startswith(‘B‘),Names)
>>> B_Name
[‘Bob‘, ‘Barbara‘]

  • 例09: lambda和map聯合使用:

>>> squares = map(lambda x:x**2,range(5))
>>> squares
[0, 1, 4, 9, 16]

  • 例10. lambda和map,filter聯合使用:

>>> squares = map(lambda x:x**2,range(10))
>>> filters = filter(lambda x:x>5 and x<50,squares)
>>> filters
[9, 16, 25, 36, 49]

  • 例11. lambda和sorted聯合使用

#按death名單裏面,按年齡來排序

#匿名函數的值返回給key,進來排序

>>> death = [ (‘James‘,32),
(‘Alies‘,20),
(‘Wendy‘,25)]

>>> sorted(death,key=lambda age:age[1]) #按照第二個元素,索引為1排序
[(‘Alies‘, 20), (‘Wendy‘, 25), (‘James‘, 32)]

  • 例12. lambda和reduce聯合使用

>>> L = [1,2,3,4]
>>> sum = reduce(lambda x,y:x+y,L)
>>> sum
10

  • 例13. 求2-50之間的素數

#素數:只能被1或被自己整除的數

>>> nums = range(2,50)
>>> for i in nums:
nums = filter(lambda x:x==i or x % i,nums)
>>> nums
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

  • 例14. 求兩個列表元素的和

>>> a = [1,2,3,4]
>>> b = [5,6,7,8]
>>> map(lambda x,y:x+y, a,b)
[6, 8, 10, 12]

  • 例15. 求字符串每個單詞的長度

>>> sentence = "Welcome To Beijing!"
>>> words = sentence.split()

>>> lengths = map(lambda x:len(x),words)
>>> lengths
[7, 2, 8]

寫成一行:

>>> print map(lambda x:len(x),‘Welcome To Beijing!‘.split())

  • 例16. 和def函數一起使用,註意其參數傳遞
  1. >>> def sayHello():
  2. ... title = ‘Hello, ‘
  3. ... union = (lambda x: title + ‘‘ + x + ‘!‘)
  4. ... return union
  5. ...
  6. >>> f = sayHello() #此處無需帶參數
  7. >>> f(‘Jerry‘) #通過修改默認參數來傳遞參數
  8. ‘Hello, Jerry!‘

  • 例17. 統計Linux系統掛載點

[[email protected] ~]# mount -v

/dev/mapper/rootVG-root on / type ext3 (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
devpts on /dev/pts type devpts (rw,gid=5,mode=620)
/dev/mapper/rootVG-tmp on /tmp type ext3 (rw)
/dev/mapper/rootVG-var on /var type ext3 (rw)
/dev/cciss/c0d0p1 on /boot type ext3 (rw)
tmpfs on /dev/shm type tmpfs (rw,size=90%)

>>> import commands
>>> mount = commands.getoutput(‘mount -v‘)
>>> lines = mount.splitlines()
>>> point = map(lambda line:line.split()[2],lines)
>>> print point
[‘/‘, ‘/proc‘, ‘/sys‘, ‘/dev/pts‘, ‘/tmp‘, ‘/var‘]

寫成一行:

>>> print map(lambda x:x.split()[2],commands.getoutput(‘mount -v‘).splitlines())

效率問題:

#比較def函數和lambda函數效率問題

  1. import time
  2. # 測試的Def函數
  3. def square1(n):
  4. return n ** 2
  5. # 測試的Lambda函數
  6. square2 = lambda n: n ** 2
  7. print(time.time())
  8. # 使用Def函數
  9. i = 0
  10. while i < 1000000000:
  11. square1(100)
  12. i += 1
  13. print(time.time())
  14. # 使用lambda函數
  15. i = 0
  16. while i < 1000000000:
  17. square2(100)
  18. i += 1
  19. print(time.time())

輸出結果:

1413272496.27
1413272703.05 (Def 函數:207s)
1413272904.49 (Lambda函數:201s)

從上面可以看出,兩者的所需的時間差不多,效率絲毫不受影響.

晦澀屬性:

出於簡明的考慮,避免在lambda中嵌套lambda

  1. >>> action = (lambda x: (lambda y: x+ y))
  2. >>> action(99)(2)
  3. 101

像上面的例子,出於代碼的簡潔性考慮,最好換成下面的

  1. >>> def f(x):
  2. ... return (lambda y: x + y)
  3. ...
  4. >>> g = f(99)
  5. >>> g(2)
  6. 101

難點例子:

from itertools import product
map(lambda p: ‘‘.join(i + j for i, j in zip(‘abcd‘, p)) + ‘e‘, product([‘.‘, ‘‘], repeat = 4))

Python匿名函數詳解