Python学习笔记22:函数式编程
这里的函数式编程,并非指面向过程编程。而更多的是一种将函数作为一等对象的编程语言中,函数在编程中灵活性体现的一种描述。
一等对象
关于什么是一等对象,《Fluent Python》一书给出的解释是——如果一个对象是一等对象,将具有以下特性:
-
运行时创建
-
能赋值给变量或容器中的元素
-
能作为函数参数进行传递
-
能作为函数的返回值结果
在我的印象中,Javascrip和Python中的函数都具有此类特性,具有相当高的灵活性。而其它语言都缺少这样或那样的特性。
函数对象
正如在Python学习笔记0:变量中阐述过的那样,Python是门基于对象的语言,而函数也是对象。
def hello():
'''你好'''
print("Hello world!")
print(hello)
print(type(hello))
print(hello.__doc__)
# <function hello at 0x000001D402AF39D0>
# <class 'function'>
# 你好
通过type
我们可以清楚地看到自定义函数hello
是function
类的一个实例,而且可以访问其属性,比如__doc__
。
此外,函数对象还可以作为参数和返回值,这在构建函数修饰符的时候有明确体现,需要回顾和了解的可以阅读Python学习笔记11:函数修饰符,此处不做过多赘述。
高阶函数
我们已经说明了函数本身是可以作为参数进行传递的,而通过参数接收函数的函数被称作高阶函数。
我知道这么说很绕,但意思不难理解。
在Python的常用函数中有这么几个高阶函数:
sorted
sorted
常用于序列排序,之前在Python学习笔记19:列表 III中我们介绍过。
我们知道,sorted
可以指定一个参数key
,改变默认的排序原则。
l = ["aa", "b", "ccc"]
print(sorted(l, key=len))
# ['b', 'aa', 'ccc']
就像上面展示的那样,key
通过接收单参数函数对象的方式改变了sorted
的默认排序原则。
所以说sort
是一个高阶函数。
map
map
函数的作用如同其名称揭示的那样,可以将一个函数应用于一个可迭代对象。
persons = [('Jack chen', 16, 'actor'),
('Brus lee', 20, 'engineer')]
def formatPerson(person: tuple):
return "name:%s,age:%s,actor:%s" % (person[0], str(person[1]), person[2])
formatPersons = list(map(formatPerson, persons))
print(formatPersons)
# ['name:Jack chen,age:16,actor:actor', 'name:Brus lee,age:20,actor:engineer']
map的返回值同样是一个可迭代对象,所以我们可以用list()
承接并进一步处理。
这个例子中的formatPerson
函数比较简单,所以我们也可以用匿名函数来改写:
persons = [('Jack chen', 16, 'actor'),
('Brus lee', 20, 'engineer')]
formatPersons = list(map(lambda person: "name:%s,age:%s,actor:%s" % (
person[0], str(person[1]), person[2]), persons))
print(formatPersons)
# ['name:Jack chen,age:16,actor:actor', 'name:Brus lee,age:20,actor:engineer']
但这样的代码可读性不高,幸运的是Python3提供了两个新的特性:推导式和生成器。我们完全可以用推导式完成类似的工作,还更具有可读性。
persons = [('Jack chen', 16, 'actor'),
('Brus lee', 20, 'engineer')]
formatPersons = ["name:%s,age:%s,actor%s" % (name,age,career) for name,age,career in persons]
print(formatPersons)
# ['name:Jack chen,age:16,actor:actor', 'name:Brus lee,age:20,actor:engineer']
所以,因为推导式和生成器的存在,map
在Python3中的使用频率不高。
reduce
reduce
函数接受一个两参数函数,会用这个函数来处理一个可迭代对象。
和map
不同的是,reduce
函数的处理逻辑是“累积式处理”。即每处理完一个可迭代对象的元素,会把其结果作为下一次处理中的一个参数。
这种处理方式的最常见概念是数学中的阶乘。
我们使用reduce
来完成一个阶乘函数:
from functools import reduce
def factorial(n):
return reduce(lambda a, b: a*b, range(1, n+1))
print(factorial(1))
print(f