4.17 函数式编程
与Java、C#等流行的编程语言一样,Python不是纯粹的函数式语言。但是,它提供了“函数样式”的功能,可以帮助我们编写不易出错、更加简洁以及更易于阅读、调试和修改的代码。函数式编程也更容易实现并行化,以便在多核处理器上获得更好的性能。下表列出了Python的大部分与函数式编程有关的功能,括号中的数字是涉及相应功能的章节。
函数式编程主题
避免副作用(4)
关闭
声明式编程(4)
装饰器(10)
字典推导式(6)
filter/map/reduce
(5)
functools
模块
生成器表达式(5)
生成器函数
高阶函数(5)
不可变性(4)
内部迭代(4)
迭代器(3)
itertools
模块(16)
lambda
表达式(5)
惰性求值(5)
列表推导式(5)
operator
模块(5、11、16)
pure
函数(4)
range
函数(3、4)
约简(3、5)
集合推导式(6)
以上这些功能中的绝大部分在本书中都有介绍,包括代码示例和文字介绍。我们已经使用了列表、字符串和内置函数range
迭代器以及几个约简函数(sum
、len
、min
和max
)。接下来讨论一下声明式编程、不可变性和内部迭代。
做什么与如何做
随着所执行的任务变得越来越复杂,完成任务的代码可能变得越来越难以阅读、调试和修改,并且包含错误的可能性也越来越大。此时,指定代码的工作方式会变得非常复杂。
函数式编程让我们只需简单地说出想要做什么,而隐藏了许多任务执行的细节。通常,库代码会帮我们完成“如何做”这个环节,这样可以避免许多错误。
在许多其他编程语言的for
语句中,通常需要指定计数器控制的所有细节,包括:设置控制变量、初始化控制变量、设置控制变量的增量,以及如何使用控制变量确定是否继续迭代(循环继续条件)。这种迭代方式称为外部迭代,容易出现错误。例如,提供了不正确的初始化程序、增量或循环继续条件等都可能导致错误出现。外部迭代会改变(即修改)控制变量,而for
语句的套件也会改变其他变量,每次修改变量都有可能导致错误出现。函数式编程则强调不可变性,换句话说,就是函数式编程避免了修改变量值的操作。我们将在下一章详细说明这一点。
Python的for
语句和range
函数隐藏了大多数计数器控制的迭代细节。可以指定生成值的范围以及应接收每个生成值的变量。函数range
知道如何生成这些值。同样,for
语句也知道如何从range
中获取每个值以及如何在没有更多值时停止迭代。指定做什么而不是如何做,是内部迭代的一个重要思想,也是函数式编程中一个关键的概念。
Python内置函数sum
、min
和max
均使用内部迭代。要计算列表grades
元素的总和,只需声明要执行的操作,即sum(grades)
。函数sum
知道如何遍历列表并将每个元素添加到变化的total
中。说出想做什么而不是如何做,这种编程方式被称为声明式编程。
pure函数
在pure
函数式编程语言中,我们会专注于编写pure
函数。所谓pure
函数,是指其结果仅取决于传递给它的参数,同时,给定一个或几个特定的参数,也总能生成相同的结果。例如,内置函数sum
的返回值仅取决于传递给它的可迭代对象。给定一个列表[1,2,3]
,无论调用多少次,sum
总是返回6。pure
函数的另一个特点是没有副作用。例如,即使将可变列表传递给pure
函数,列表在函数调用之前和之后也不会发生任何改变。当调用pure
函数sum
时,它不会修改其参数:
在下一章中,我们将继续使用函数式编程的概念。此外,我们还将看到函数事实上也是对象,可以作为数据传递给其他函数。