今天是51假期,我开启了新的一章,✌️!
第五章 一等函数
编程语言理论家将“一等对象”定义为满足下述条件的程序实体:
- 在运行时创建
- 能赋值给变量或者数据结构中的元素
- 能作为参数传给函数
- 能作为函数的返回结果
因此,按照以上的标准,整数、字符串和字典都是一等对象。
5.1 5.1 5.1 把函数视作对象
>>> def func1(n):
... ''' return n!'''
... n = n+1
... return n
...
>>> func1(1)
2
>>> func1.__doc__
' return n!'
>>> type(func1)
# <class 'function'>
从以上实例中,我得知函数是一个function类型的对象,并且我可以用__doc__获取它的文档属性。
__doc__用于生成对象的帮助文本。
因此,该函数就符合一等对象的全部特征。
可以赋值给变量,也可以作为参数传给函数。
>>> my_func = func1
>>> my_func
<function func1 at 0x103c67b70>
>>> func1
<function func1 at 0x103c67b70>
>>> func1(func1(1))
3
有了一等函数,就可以使用函数式风格来编程。
5.2 5.2 5.2 高阶函数
接受函数作为参数,或者将函数作为结果返回的函数是高阶函数。
我们在第二章提到的sorted()排序的函数也是高阶函数,因为它会将key作为参数会应用到各个元素中进行排序。
如下所示:
>>> fruits = ['strawberry','apple','watermalon','lemon']
>>> sorted(fruits, key=len)
['apple', 'lemon', 'strawberry', 'watermalon']
任何单个参数的函数都可以作为key参数的值。
>>> def reverse(word):
... return word[::-1]
...
>>> reverse('my world')
'dlrow ym'
>>> sorted(fruits, key=reverse)
['apple', 'watermalon', 'lemon', 'strawberry']
我们平常比较常用的高阶函数有filter,map,reduce等。其中map和filter还是内置函数,但是由于引入了列表推导和生成式,他们变得不是特别重要了。
下面比较了两种方式:
>>> list(map(func1, range(6)))
[1, 2, 3, 4, 5, 6]
>>> [func1(n) for n in range(6)]
[1, 2, 3, 4, 5, 6]
>>> list(map(func1, filter(lambda n:n%2, range(6))))
[2, 4, 6]
>>> [func1(n) for n in range(6) if n % 2]
[2, 4, 6]
map和filter返回的是一个生成器,因此目前经常会被生成器表达式所取代。
在python2中,reduce是一个内置函数,而在python3中,被放到了functools模块中。
>>> from functools import reduce
>>> from operator import add
>>> reduce(add, range(100))
4950
>>> sum(range(100))
4950
sum和reduce的通用思想都是将某个操作连续应用在序列中的元素上,并且累计之间的结果,返回成一个值。
同样的还有all和any函数:
- all(iterable)
如果iterable中元素都是真值,就返回True - any(iterable)
只要iterable中有元素是真值,就返回True
>>> all(range(100))
False
>>> any(range(100))
True
>>> all(range(1,2))
True
>>> any(range(1))
False
在逻辑中,真值(truth value),又称逻辑值(logical value),是指示一个陈述在什么程度上是真的。在计算机编程上多称做布林值、布尔值。
5.3 5.3 5.3 匿名函数
lambda关键式在python表达式中创建匿名函数。
然而,python简单的句法限制了lambda函数的定义体中只能使用纯表达式。也就是说,lambda函数的定义体中不能赋值,也不能使用while,try等语句。
刚才我们那个反转单词的例子就可以用lambda作为key
>>> sorted(fruits, key=lambda word:word[::-1])
['apple', 'watermalon', 'lemon', 'strawberry']
在使用lambda时,由于它的一些局限性,因此建议走以下步骤:
- 编写注释,说明下lambda表达式的功能作用
- 研究一会儿注释,找出一个名称来概括注释
- 将lambda表达式转换成def语句,使用那个名称来定义函数
- 删除注释
lambda句法只是语法糖:与def一样,lambda表达式会创建函数对象。
语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的术语,指向计算机语言中添加某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常而言,使用语法糖能够增加程序的可读性,从而减少代码出错的机会。 举个例子,在C语言里面我们经常用a[i][j]表示((a+i)+j),a[i][j]这种写法简洁明了,更容易被人理解。