Python 匿名函数、内置高阶函数、偏函数

匿名函数 lambda

维基百科定义:

在计算机编程中,匿名函数(英语:anonymous function)是指一类无需定义标识符(函数名)的函数或子程序,普遍存在于多种编程语言中。

Python中的匿名函数就是lambda,这个名称来源于数学中的λ演算。Lambda(大写Λ,小写λ,中文音译:兰布达,是第十一个希腊字母)。

示例:

1
2
3
>>> func = lambda x, y: x + y
>>> func(2,3)
5

上面的func定义等价于:

1
2
3
4
5
>>> def func(x, y):
... return x + y
...
>>> func(2,3)
5

lambda函数用法很简单,大部分情况下都不会像上面示例定义func,而是直接把匿名函数当参数使用。

下面分享点lambda的特殊用法:

lambda定义的函数大部分情况都是需要参数的,如果不需要参数要怎么写呢?

1
2
3
>>> func = lambda: 'No parameter'
>>> func()
'No parameter'

如果你想在lambda函数里面抛异常,要怎么实现呢?

1
2
3
4
5
6
7
>>> func = lambda: (_ for _ in ()).throw(Exception('error'))
>>> func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
File "<stdin>", line 1, in <genexpr>
Exception: error

内置高阶函数 map reduce filter sorted

维基百科定义:

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:

  • 接受一个或多个函数作为输入
  • 输出一个函数

map 函数

map(function, iterable, …)

函数作用: 对可迭代对象iterable中的item依次执行function,将执行结果组成一个List返回。

示例:

1
2
3
4
5
6
>>> map(lambda x: x+x, range(1,4)) # function单个参数
[2, 4, 6]
>>> map(lambda x,y: x+y, range(1,4), range(3,0,-1)) # function多个参数
[4, 4, 4]
>>> map(lambda x,y: (x,y), range(1,4), range(3,0,-1)) # function返回值为tuple
[(1, 3), (2, 2), (3, 1)]

在Python 3中,map函数返回值不再是List,而是iterator。

1
2
3
4
5
6
>>> map(lambda x: x+x, range(1,4))
<map object at 0x7fe223d405c0>
>>> list(map(lambda x: x+x, range(1,4)))
[2, 4, 6]
>>> [*map(lambda x: x+x, range(1,4))]
[2, 4, 6]

reduce 函数

reduce(function, iterable[, initializer])

函数作用: 对可迭代对象iterable中的item顺序迭代执行调用function,返回accum_value。如果有initializer,则将initializer作为accum_value的初始值。

示例:

1
2
3
4
>>> reduce(lambda x,y: x+y, range(1,10))
45
>>> reduce(lambda x,y: x+y, range(1,10), 100)
145

filter 函数

filter(function, iterable)

函数作用: 对可迭代对象iterable中的item依次执行function,将执行结果为True的item组成一个List/String/Tuple(取决于iterable的类型)返回。

function不为None时,等价于下面的表达式:

[item for item in iterable if function(item)]

function为None时,等价于下面的表达式:

[item for item in iterable if item]

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> filter(lambda x: x%3==1, range(1,10))
[1, 4, 7]

>>> L = [0, 23, 232, 88, None, 0, 26, 11]
>>> filter(None, L)
[23, 232, 88, 26, 11]

>>> [i for i in L if i is not None]
[0, 23, 232, 88, 0, 26, 11]

>>> from operator import is_not
>>> from functools import partial
>>> filter(partial(is_not, None), L)
[0, 23, 232, 88, 0, 26, 11]

sorted 函数

sorted函数之前的博文Python 排序方法list.sort()和sorted()有介绍过,在此就不再赘述了。

zip 函数

zip函数其实不算是高阶函数,但也比较常用,在此一并介绍了。

zip([iterable, …])

函数作用: 将可迭代对象iterable作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

示例:

1
2
3
4
5
6
7
8
9
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zip(a,b)
[(1, 4), (2, 5), (3, 6)]
>>> zip(a,c)
[(1, 4), (2, 5), (3, 6)]
>>> zip(*zip(a,b)) # 与zip相反,可理解为解压,返回二维矩阵式
[(1, 2, 3), (4, 5, 6)]

偏函数 functools.partial

functools.partial(func[,args][, *keywords])

偏函数是从Python2.5引入的一个概念,通过functools模块被用户调用。

偏函数是将所要承载的函数作为partial()函数的第一个参数,原函数的各个参数依次作为partial()函数后续的参数。

示例:

1
2
3
4
5
6
7
8
9
10
11
>>> from functools import partial
>>> bin2dec = partial(int, base=2)
>>> bin2dec('0b1001')
9
>>> bin2dec('1001')
9
>>> hex2dec = partial(int, base=16)
>>> hex2dec('0x32')
50
>>> hex2dec('32')
50

下面这种情况,map函数和partial函数配合使用更Pythonic。

有一个iterable需要用function(x, y)批量处理,iterable中的item作为参数y,参数x此处需要传入变量var

如果不用partial,实现代码如下:

1
2
3
>>> var = 2
>>> map(lambda x,y: pow(x,y), [var]*3, range(1,4))
[2, 4, 8]

partial实现代码如下:

1
2
3
>>> var = 2
>>> map(partial(lambda x,y: pow(x,y), var), range(1,4))
[2, 4, 8]