Python程序设计:人工智能案例实践
上QQ阅读APP看书,第一时间看更新

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迭代器以及几个约简函数(sumlenminmax)。接下来讨论一下声明式编程、不可变性和内部迭代。

做什么与如何做

随着所执行的任务变得越来越复杂,完成任务的代码可能变得越来越难以阅读、调试和修改,并且包含错误的可能性也越来越大。此时,指定代码的工作方式会变得非常复杂。

函数式编程让我们只需简单地说出想要做什么,而隐藏了许多任务执行的细节。通常,库代码会帮我们完成“如何做”这个环节,这样可以避免许多错误。

在许多其他编程语言的for语句中,通常需要指定计数器控制的所有细节,包括:设置控制变量、初始化控制变量、设置控制变量的增量,以及如何使用控制变量确定是否继续迭代(循环继续条件)。这种迭代方式称为外部迭代,容易出现错误。例如,提供了不正确的初始化程序、增量或循环继续条件等都可能导致错误出现。外部迭代会改变(即修改)控制变量,而for语句的套件也会改变其他变量,每次修改变量都有可能导致错误出现。函数式编程则强调不可变性,换句话说,就是函数式编程避免了修改变量值的操作。我们将在下一章详细说明这一点。

Python的for语句和range函数隐藏了大多数计数器控制的迭代细节。可以指定生成值的范围以及应接收每个生成值的变量。函数range知道如何生成这些值。同样,for语句也知道如何range中获取每个值以及如何在没有更多值时停止迭代。指定做什么而不是如何做,是内部迭代的一个重要思想,也是函数式编程中一个关键的概念。

Python内置函数summinmax均使用内部迭代。要计算列表grades元素的总和,只需声明要执行的操作,即sum(grades)。函数sum知道如何遍历列表并将每个元素添加到变化的total中。说出想做什么而不是如何做,这种编程方式被称为声明式编程

pure函数

pure函数式编程语言中,我们会专注于编写pure函数。所谓pure函数,是指其结果仅取决于传递给它的参数,同时,给定一个或几个特定的参数,也总能生成相同的结果。例如,内置函数sum的返回值仅取决于传递给它的可迭代对象。给定一个列表[1,2,3],无论调用多少次,sum总是返回6。pure函数的另一个特点是没有副作用。例如,即使将可变列表传递给pure函数,列表在函数调用之前和之后也不会发生任何改变。当调用pure函数sum时,它不会修改其参数:

在下一章中,我们将继续使用函数式编程的概念。此外,我们还将看到函数事实上也是对象,可以作为数据传递给其他函数。