:
说到微积分,经常会和函数式编程纠缠不清。这种设计理念强调抛弃变量和状态,用纯函数的递归系统来构建程序(个人理解)。虽然函数式编程和面向对象编程背道而驰,但并不妨碍借鉴一些有价值的内容。换句话说,不能因为它的存在就认为它是一种函数式编程语言,只是因为它在某些细节上更高效而被引入。比如用来定义匿名函数,和标题提到的apply()等内置函数一起构建一些程序结构。
匿名函数与标准方式声明的函数的区别在于,它不需要def语句,也不需要名字来引用它,直接使用语句就可以获得函数对象,其语法为:
[参数1[,参数2…]]:
参数是可选的,冒号后面跟着一个表达式,函数返回这个表达式的值,在def语句中,相当于:
def func([arg1[,arg2…]]):
可以看到函数没有中间状态,不适合构建过于复杂的函数,因为它们的函数体只有一个表达式。因此,它们大多用于构建临时的、简单的、不可重用的小函数。虽然原则上你可以给函数起一个别名,如下所示,以供后续引用。但如果你打算重用这个函数,为什么不使用 def 语句定义一个标准函数,它具有更多的功能并且更易于维护。
>>> foo = lambda a,b: a+b
>>> foo(1,2)
3
(), 地图(), ():
apply()函数放在最后,因为涉及变长参数,并且和其他三个函数功能不一样,而()、map()、()三个内置函数的功能同属一类,都是对可迭代对象进行处理并返回结果。
( or None, ) --> 该函数正如其名称一样,使用可迭代对象中的每个元素作为参数调用布尔函数,返回迭代器中所有返回 True 的元素。如果为 None,则返回值为 True 的元素。示例:
>>> a = filter(lambda x:x>2,[1,2,3,4])
>>> type(a)
>>> for i in a:print(i)
3
4
>>>
在之前的版本中,() 函数返回的是一个列表,但后来改为返回一个迭代器,所以上面的例子使用 for 语句来显示结果。关于返回迭代器还有一点需要注意,就是上面例子中的 a 中的元素并不是在赋值时一次生成的,所以如果使用的元素调用会产生异常,那么这个异常其实是在 for 循环中抛出的。可以看出,在这种“过滤元素”的应用环境中,我们需要的函数形式很简单,只有一个表达式,所以使用 是一个不错的选择。(其实下面两个函数也是一样)
map(func, *) --> map 将函数 func 应用于 的每个元素,并以迭代器的形式返回结果。请注意,您可以在此处提供多个参数。如果这样做,当您调用 func 时,它将依次从每个元素中取出一个元素,直到用尽最短的元素。因此 func 的参数数量应等于 的数量。
>>> a = map(lambda x,y:x+y,[1,2,3],[3,2,1])
>>> type(a)
>>> for i in a:print(i)
4
4
4
(, [, ]) –> value 函数是:接受两个参数,第一个是,第二个是 的第一个元素。如果没有提供,则取前两个元素。然后将本次调用的返回值作为第一个参数传递,第二个参数是 的下一个元素。如此循环下去,返回最终的值。因为 () 函数不再是 中的内置函数,需要 from 才能使用它,所以这里就不举例了。
其实不仅如此,在当前版本中这三个函数已经没什么用了。()和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() 比 () 更糟糕,在 中已经不存在了。这是因为它从 1.6 版本开始就不再使用了。我们在这里仍然提到它只是为了介绍下一个主题:可变长度参数。事实上,在 1.6 之前,函数不支持可变长度参数,apply() 就是为此而生的。它可以使用可变长度参数来调用函数。
可变长度参数:
可变长度参数意味着:调用函数时不知道要传入多少个参数,可能没有,也可能有 100 多个。比如计算电子账单总额时,谁知道会有多少项呢?虽然像这样的问题,还有很多其他方法可以将金额加在一起,但使用单个函数来实现它总是能收获额外的好处。而且,虽然可变长度参数的功能也可以用元组来实现,但下面介绍的方法可以做得更好。定义函数时可以使用的参数的完整形式如下:
定义函数(,,*,**):
这四种参数形式都是独立可选的,前两种就不展示了,后面带*和**的是变长参数,位置上带*的必须放在不带*的后面,否则会报错,比如模块里有一个add()函数:
add(a, b)——与 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
从上面的例子就可以看出*的作用了,只要参数中有*args,那么函数就会自动接受所有非关键字参数,并且把接收到的参数全部放入一个元组中。
但是这个函数和 add() 相比有一个缺点,add() 不仅可以加数字,还可以连接字符串,而我们定义的这个只能处理数字。所以接下来我们要把位置参数 () 和变长非关键字参数 (*) 结合起来使用,这也是一个能体现它们之间联系的例子:
>>> 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) 像这样。
关键字参数的表现与非关键字参数相同,这里就不再赘述了。
扫一扫在手机端查看
-
Tags : Python lambda apply filter 可变长参数 lionets Python里的匿名函数(lambda)与apply() filter() map() reduce(),以及函数的可变长参数 - 喵酱的书架 OSCHINA博客
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。