lambda用法及其高阶函数

lambda函数

1、lambda 语法

lambda arg1,arg2,…argn(传入的参数):expression(要执行的语句)

匿名函数不需要return来返回值,表达式expression执行完的结果就是返回值。

# 普通python函数
def func(a,b,c):
    return a+b+c
 
print func(1,2,3)
# 返回值为6
 
# lambda匿名函数
f = lambda a,b,c:a+b+c

print f(1,2,3)
# 返回结果为6

1.1 参数arg

[arg…] 是参数列表,它的结构与 Python 中函数(function)的参数列表是一样的。
[arg…] 可以有非常多的形式。例如:

  • a, b 函数输入是a和b
  • a=1, b=2
  • *args 输入是任意个数参数
  • **kwargs 输入是任意键值对参数
  • a, b=1, *args
  • 函数没有输入参数

1.2 参数表达式expression

expression 是一个参数表达式,表达式中出现的参数需要在[arg......]中有定义,并且表达式只能是单行的,只能有一个表达式。
以下都是合法的表达式:

  • 1
  • None
  • a + b
  • sum(a)
  • 1 if a >10 else 0
  • m for m in xxxxx

1.3 常见的lambda函数示例:

lambda x, y: x*y			# 函数输入是x和y,输出是它们的积x*y
lambda:None					# 函数没有输入参数,输出是None
lambda *args: sum(args)		# 输入是任意个数参数,输出是它们的和(隐性要求输入参数必须能进行算术运算)
lambda **kwargs: 1			# 输入是任意键值对参数,输出是1
无参匿名函数

例1、

无参匿名函数:
------
>>> t = lambda : True #分号前无任何参数
>>> t()
True

等价于下面的def定义的函数
>>> def func(): return True
>>> func()
True

例2、

#建此字符串按照正常情形输出
>>> 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")
即
f = lambda s:' '.join(s.split());
f("this is\na\ttest")
带参匿名函数
>>> lambda x: x**3 #一个参数
>>> lambda x,y,z:x+y+z #多个参数
>>> lambda x,y=3: x*y #允许参数存在默认值

#以元组作为参数
>>> a = lambda *z:z  #参数*z表示输入参数为元组
>>> a('Testing1','Testing2')
('Testing1', 'Testing2')

匿名函数调用

#直接赋值给一个变量,然后再像一般函数调用

>>> 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!'

2、lambda 用法之高阶函数

2.1 map() 函数:

map(function, iterable, ...)

描述:map() 会根据提供的函数function 对指定序列 iterable 做映射。

以序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

参数:

  • function ----> 函数

  • iterable ----> 一个或多个序列

返回值:

  • Python 2.x 版本返回的是列表
  • Python 3.x 版本返回的是迭代器
# ===========一般写法:===========
# 1、计算平方数
def square(x):
	return x ** 2

map(square, [1,2,3,4,5])	# 计算列表各个元素的平方
# 结果:
[1, 4, 9, 16, 25]

# ===========匿名函数写法:============
# 2、计算平方数,lambda 写法
map(lambda x: x ** 2, [1, 2, 3, 4, 5])
# 结果:
[1, 4, 9, 16, 25]	 

# 3、提供两个列表,将其相同索引位置的列表元素进行相加
map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
# 结果:
[3, 7, 11, 15, 19]

2.2 reduce()函数

reduce(function, iterable[, initializer])
  • reduce() 函数会对参数序列中元素进行 累加

  • 函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:

    • 用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,
    • 得到的结果再与第三个数据用 function 函数运算,以此类推,最后得到一个结果。

参数:

  • function ----> 函数,有两个参数
  • iterable ----> 可迭代对象
  • initializer ----> 可选,初始参数

返回值:

  • 返回函数计算结果。
# ===========一般写法:===========
# 1、两数相加
def add(x, y):            
	return x + y

reduce(add, [1, 3, 5, 7, 9])    # 计算列表元素和:1+3+5+7+9
# 结果:
25

"""
===========执行步骤解析:===========
调用 reduce(add, [1, 3, 5, 7, 9])时,reduce函数将做如下计算:
1	先计算头两个元素:f(1, 3),结果为4;
2	再把结果和第3个元素计算:f(4, 5),结果为9;
3	再把结果和第4个元素计算:f(9, 7),结果为16;
4	再把结果和第5个元素计算:f(16, 9),结果为25;
5	由于没有更多的元素了,计算结束,返回结果25。
"""

# ===========匿名函数写法:===========
# 2、两数相加,lambda 写法
reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])
# 结果:
15

什么时候用reduce()?

# 当然求和运算可以直接用Python内建函数sum(),没必要动用reduce。
	
# 3、但是如果要把序列 [1, 3, 5, 7, 9] 变换成整数 13579,reduce就可以派上用场:
def fn(x, y):
	return x * 10 + y

reduce(fn, [1, 3, 5, 7, 9])
# 结果:
13579

2.3 sorted() 函数:

sorted(iterable[, cmp[, key[, reverse]]])

描述: sorted() 函数对所有可迭代的对象进行排序操作。

sort 与 sorted 区别:
sort 是 list 的一个方法,而 sorted 可以对 所有 可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,无返回值,而内建函数 sorted 方法返回的是一个 新的 list,而不是在原来的基础上进行的操作。

参数说明:

  • iterable ----> 可迭代对象。
  • cmp ----> 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0
  • key ----> 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
  • reverse ----> 排序规则,reverse = True 降序 , reverse = False 升序(默认)。

返回值:

返回重新排序的列表。

# ===========一般用法:===========
# 1、简单排序
a = [5,7,6,3,4,1,2]
b = sorted(a)       # 使用sorted,保留原列表,不改变列表a的值
print(a)
[5, 7, 6, 3, 4, 1, 2] # 原列表不变
print(b)
[1, 2, 3, 4, 5, 6, 7]
# ===========匿名函数用法:===========
L=[('b',2),('a',1),('c',3),('d',4)]
# 2、利用参数 cmp 排序
sorted(L, cmp=lambda x,y:cmp(x[1],y[1]))
# 结果:
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]

---------
# 3、利用参数 key 排序
sorted(L, key=lambda x:x[1])
# 结果:
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]

---------
# 4、按年龄升序
students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
sorted(students, key=lambda s: s[2])
# 结果:
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

---------
# 5、按年龄降序
sorted(students, key=lambda s: s[2], reverse=True)
# 结果:
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

2.4 filter() 函数:

filter(function, iterable)

描述: filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。

  • 该接收两个参数,第一个为函数,第二个为序列,

  • 序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,

  • 最后将返回 True 的元素放到新列表中。

参数:

  • function ----> 判断函数。
  • iterable ----> 可迭代对象。

返回值:

  • Pyhton2.7 返回列表,
  • Python3.x 返回迭代器对象,具体内容可以查看:Python3 filter() 函数
# ===========一般用法:===========
# 1、过滤出列表中的所有奇数
def is_odd(n):
	return n % 2 == 1
		 
newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(list(newlist))
# 结果: [1, 3, 5, 7, 9]

# ===========匿名函数用法:===========
# 2、将列表[1, 2, 3]中能够被3整除的元素过滤出来
newlist = filter(lambda x: x % 3 == 0, [1, 2, 3])
print(list(newlist))
# 结果: [3]

2.5 和for连用

(1)res=[ lambda x,i=i : x*i for i in range (6) ]
第一种:带参数x

res=[ lambda x,i=i : x*i for i in range (6) ]

  • res=[ lambda x,i=i : x*i for i in range (6) ] ,获得一个函数列表
  • res[0]代表 i = 0时计算x*0的值;同理, res[1],…, res[5] 分别代表 i = 1,…,5 时的函数
  • res[1](0) 即 向函数res[1]传入参数0。

例1: 给出一个值 x ,分别计算 x 与 0~5 之间各个数的乘积

#  给出一个值 x ,分别计算 x 与 0~5 之间各个数的乘积
res=[lambda x,i=i : x*i for i in range (6)]
print(res)       #得到返回 x*i 函数的6个地址
for f in res:    #循环遍历每个地址
    print(f(2))  #对每个遍历到的函数 传递参数 x=2
#0 2 4 6 8 10

输出:0 2 4 6 8 10

这里的x+i for i in range (6)是原for…in…if…的用法

x,i为每个函数的参数,而 i 由for循环指定

相当于:

res = []
for i in range(4):
    def lam(x,y=i):   # 即 指定y=i
        return x*y    # 即 x*i
    fs.append(lam)
    
for f in res:    #循环遍历每个地址
    print(f(2))  #对每个遍历到的函数 传递参数 x=2
# 输出:0 2 4 6 8 10

输出:0 2 4 6 8 10

第二种:无参使用:

res = [lambda i=i: i*i for i in range(6)]

调用时无需输入参数,但是注意括号不能少!

res = [lambda i=i: i*i for i in range(6)]

for f in res:    #循环遍历每个地址
    print(f())   #无需输入参数,但是注意 括号不能少!

输出:0 1 4 9 16 25

相当于:

fs = []
for i in range(4):
    def lam(x=i):   # 即 i=i
        return x*x    # 即 i*i
    fs.append(lam)
(2)错误操作:res = [lambda x : x*i for i in range(6)]
第一种:带参数x
res = [lambda x : x*i  for i in range(6)]
print(res)   # 获得一个包含 x*i 函数的6个地址的列表。
for f in res:    #循环遍历每个地址
    print(f(2))  #对每个遍历到的函数 传递参数 x=2

输出:10 10 10 10 10 10

相当于:

res = []
for i in range (6):
    def lam(x): #并未指定另一个参数i的值
        return x*i
    res.append(lam)

for f in res:    #循环遍历每个地址
    print(f(2))  #对每个遍历到的函数 传递参数 x=2

每循环一次,将 lam 函数的地址存到 res 中。因为在每次循环中 lam函数都未绑定 i 的值,所以直到循环结束,i 的值为5,并将 lam 中所用到的 i 值定为 5 ,因此真正调用(例如res[0](2)的时候 i 值保持不变(为5)。

所以 无论调用的res[]是第几个函数,计算的都是 x*5。

第二种:无参使用:

res= [lambda : i*i for i in range(6)]

无需输入参数,但是注意 括号不能少!

res= [lambda : i*i for i in range(6)]

for f in res:    #循环遍历每个地址
    print(f())   #无需输入参数,但是注意 括号不能少!
#25 25 25 25 25 25

输出:25 25 25 25 25 25

相当于:

res = []
for i in range (6):
    def lam():     #并未指定i的值
        return i*i
    res.append(lam)

for f in res:    #循环遍历每个地址
    print(f())
# 输出:25 25 25 25 25 25

输出:25 25 25 25 25 25

(3)res = lambda x : [x*i for i in range(6)]

这种就比较正常啦!

只会获得一个函数,而不是(1)(2)中的函数列表

中括号括起来的只是表达式部分。

第一种:带参数x

res = lambda x : [x*i for i in range(6)]

res = lambda x : [x*i  for i in range(6)]
res(2)
# 输出:[0, 2, 4, 6, 8, 10]

输出:[0, 2, 4, 6, 8, 10]

相当于

def res(x):
    return [x*i  for i in range(6)]
res(2)
# 输出:[0, 2, 4, 6, 8, 10]
第二种:无参使用:

res = lambda : [x for x in range(5)]

  • 只获得一个函数,其中函数表达式是[x for x in range(5)]
  • 无需输入参数
res = lambda : [x  for x in range(5)]
res()

输出:[0, 1, 2, 3, 4]

相当于 直接return这个列表推导式

def res():
    return [x  for x in range(5)]
res()

3、复习一下列表推导式:for…in…if语法(不使用lambda)

[expression for x in X [if condition] for y in Y [if condition] ... for n in N [if condition]]

上面按照从左至右的顺序,分别是外层循环到内层循环

称为 列表推导式

2.6.1 带有 if 语句

可以在 for 语句后面跟上一个 if 判断语句,用于过滤掉那些不满足条件的结果项。

例如,我想去除列表中所有的偶数项,保留奇数项,可以这么写:

>>> L = [1, 2, 3, 4, 5, 6]
>>> L = [x for x in L if x % 2 != 0]
>>> L
[1, 3, 5]
2.6.2 带有 for 嵌套

在复杂一点的列表推导式中,可以嵌套有多个 for 语句。按照从左至右的顺序,分别是外层循环到内层循环。

例如:

>>> [x + y for x in 'ab' for y in 'jk']
['aj', 'ak', 'bj', 'bk']
2.6.3. 既有 if 语句又有 for 嵌套: for…in…if…

列表推导式可以带任意数量的嵌套 for 循环,并且每一个 for 循环后面都有可选的 if 语句。

通用语法:

[ expression for x in X [if condition]
             for y in Y [if condition]
             ...
             for n in N [if condition] ]

例如,下面的代码输出了 0~4 之间的偶数和奇数的组合。

>>> [(x, y) for x in range(5) if x % 2 == 0 for y in range(5) if y % 2 == 1]
[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]

等价于下面的一般 for 循环:

>>> L = []
>>> for x in range(5):
...     if x % 2 == 0:
...         for y in range(5):
...             if y % 2 == 1:
...                 L.append((x, y))
>>> L
[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
2.6.4. 列表推导式生成矩阵

生成矩阵的方式有多种,例如手动赋值、一般 for 循环,还有就是列表推导式。如果我们要用列表推导式生成下面的矩阵,可以怎么写?

>>> M = [[1, 2, 3],
... [4, 5, 6],
... [7, 8, 9]]

一种方法是:

>>> M = [[x, x+1, x+2] for x in [1, 4, 7]]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

矩阵的列数少时可以使用这种方法。

如果矩阵的列数较多,我们可以使用另外一种方式:在循环变量的表达式中使用列表推导式。

具体代码如下:

>>> M = [[y for y in range(x, x+3)] for x in [1, 4, 7]]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
123

与之前带 for 嵌套的语法不同,这个例子中,实际使用的是最基本的 [expression for x in L] 语法,只有一个 for 语句。

复杂的地方在于前面的变量表达式 expression 不再是简单的变量运算,而是一个列表推导式,在这个例子中就是 [y for y in range(x, x+3)]

内层的列表推导式返回一个行向量,而这些行向量经由外层的列表推导式,最终形成一个二维列表,也就是我们想要的矩阵。

参考:
Python 之 lambda 函数完整详解 & 巧妙运用_lambda函数python_Nick Peng的博客-CSDN博客