提到 Lambda演算,更多时候是与函数式编程纠缠在一块儿的。这种设计思想讲究抛弃变量和状态,使用纯函数的递归系统来构建程序(我的理解)。虽然函数式编程与 Python 的面向对象背道而驰,但并不妨害 Python 借鉴其中某些有价值的内容。便是说,并不能由于 lambda 的存在就认为 Python 是一门函数式编程语言,它只是由于在某些细节上显得更有效率而被引入的。好比 Python 里用 lambda 来定义匿名函数,并与标题中提到的 apply() 等内建函数一块儿构建一些程序结构。python
匿名函数与标准方式声明的函数区别在于,不须要使用 def 语句,也不须要一个名字来引用它。使用 lambda 语句能够直接获得一个函数对象,它的语法是:express
lambda [arg1[,arg2…]]: expression编程
参数无关紧要,冒号后面是一个表达式,函数的做用就是返回这个表达式的值。在 def 语句下等同于:app
def func([arg1[,arg2…]]):return expression编程语言
能够看到 lambda 函数没有中间状态,也不适合构建过于复杂的函数,由于它的函数体只有一个表达式。因此应用 lambda 的场合更可能是构建一些临时的、简单的和无需复用小函数。虽然原则上能够给 lambda 函数起别名,就像下面这样,以备后续引用。但若是你打算重复利用这个函数,干吗不用 def 语句定义一个标准函数呢,那样功能更多且更易维护。函数式编程
>>> foo = lambda a,b: a+b >>> foo(1,2) 3
apply() 函数由于涉及到可变长参数,而且与这三个函数的做用不一样,所以放到最后。filter(), map(), reduce() 这三个内建函数的功能属于一类,都是处理可迭代对象,而后返回结果。函数
filter(function or None, iterable) --> filter object 的功能就和它的名字同样,使用可迭代对象 iterable 中的每个元素做为参数来调用布尔函数 function,并将全部返回 True 的元素放在一个迭代器中返回。若是 function 为 None,则将 iterable 中值为 True 的元素返回。例:设计
>>> a = filter(lambda x:x>2,[1,2,3,4]) >>> type(a) <class 'filter'> >>> for i in a:print(i) 3 4 >>>
在之前的版本中 filter() 函数返回的是一个列表,但 Python3 改成了返回一个迭代器,因此上面的例子使用了 for 语句来显示结果。另外返回迭代器的一个注意点就是:上例中的 a 中的元素并非在赋值的时候一次性生成的,所以若是使用 iterable 的元素调用 function 会产生异常的话,那么该异常实际会在 for 循环中被抛出。能够看到在这种“过滤元素”的应用环境中,咱们须要的函数形式很是简单,只有一条表达式,因此使用 lambda 是个不错的选择。(实际下面的两个函数也是同样)3d
map(func, *iterables) --> map object 的功能是将函数 func 做用于 iterable 的每个元素,并将结果用迭代器返回。注意这里能够提供多个 iterable,若是这样作,调用 func 的时候就会从每一个 iterable 中依次取一个元素,直到最短的 iterable 耗尽。因此这里 func 的参数个数应该等于 iterable 的个数。code
>>> a = map(lambda x,y:x+y,[1,2,3],[3,2,1]) >>> type(a) <class 'map'> >>> for i in a:print(i) 4 4 4
reduce(function, sequence[, initial]) –> value 的功能是:function 接受两个参数,第一个是 initial,第二个是 sequence 的第一个元素。若是没有提供 initial ,那么就取前两个 sequence 的元素。而后此次调用的返回值再做为第一个参数传递给 function,第二个参数则是 sequence 的下一个元素。这样循环直到 sequence 耗尽,并将最终的值返回。由于 reduce() 函数在 Python3 中已经不是内建函数了,想要使用的话须要 from functools import reduce,因此这里就不举例了。
实际上不仅 reduce,这三个函数在如今的版本中均可以说已经没什么用了。filter() 和 map() 均可以由列表解析(生成器表达式)取代,并且明显列表解析更高级好用。因此通常知道这几个函数是干嘛用的就够了,基本不必去实际使用他们。不过下面用来取代 map() 的列表解析示例貌似只能用于单容器的情况,多容器的好比上面那个 map() 的例子该怎么写我想不出。。。
>>> [x for x in [1,2,3,4] if x>2]# filter [3, 4] >>> [x+1 for x in [1,2,3]]# map [2, 3, 4]
apply() 比 reduce() 还惨,在 functools 里都已经不存在了。这是由于早在 1.6 版本他就已经失去做用。咱们这里还要提它,仅是为了引出下面的话题:可变长参数。其实在 1.6 之前,函数还不支持可变长参数,而 apply() 就是干这个用的,他可使用可变长参数来调用函数。
可变长参数的意思就是:我在调用函数的时候不知道要传多少个参数进来,可能没有,也可能 100 多个。好比一张电子帐单,算总额的时候谁知道会有多少项呢。相似这种问题虽然有不少种其余方法把金额加到一块儿,但使用单一函数来实现总能收获到多余的好处。并且虽然用一个元组也能够实现变长参数的功能,但接下来介绍的方式能作的更好。定义一个函数时可以使用的形参彻底体以下:
def func(positional_args, keyword_args, *tuple_grp_nonkw_args, **dict_grp_kw_args):
这四种参数形式都是独立可选的。前两个不表,后面带个 * 和带 ** 的就是变长参数了。在位置上,带 * 的必须放在不带 * 的后面,不然会报错。举个栗子,operator 模块里有个 add() 函数:
add(a, b) -- Same as a + b.
该函数只接受两个参数,若是使用可变长参数的话,咱们就能让它接受无限个参数并返回他们的和:
>>> def add(*args): result = 0 for num in args: result += num return result >>> add(1,2,3,4) 10 >>> add(*(1,2,3,4)) 10 >>> add(1,2,*(3,4)) 10
从上面的例子能够看出 *tuple_grp_nonkw_args 的做用。只要你的形参里有 *args 这种设定,函数就自动变得对非关键字参数来者不拒。并把接收到的全部参数统一放在一个元组里。
不过这个函数较 operator 里的 add() 有个不足之处,就是那个 add() 除了加数字,还能链接字符串,而咱们定义的这个就只能处理数字。因而,接下来就要把位置参数(positional_args)和可变长非关键字参数(*tuple_grp_nonkw_args)一块儿用了,这也是能体现他们之间联系的一个例子:
>>> def add(first,*args): result = first checked = type(first) for item in [x for x in args if type(x)==checked]: result += item return result >>> add(1,2,3,4) 10 >>> add('1','2','3','4') '1234' >>> add(1,2,'3','4') 3 >>> add(*(1,2,3,4)) 10
这里咱们从 *args 里独立出来了一个非关键字参数,并把它命名为 first,再以后的参数只有和 first 同类型的才会加在一块儿。能够看到这时的 *args 自动让出了第一个参数给 first,而只包含剩余的参数,不论你是单独传入第一个参数,仍是用 *()的方式一股脑传入,函数内部对待他们的方式都是同样的。
忽然想到上面的例子,int 和 float 参数仍是加不到一块儿。因此能够改一下断定:if type(x) in (int,float) 这样。
而关键字参数的表现和非关键字的同样,这里就不赘述了。