Python 不可变对象

Python 不可变对象,函数式编程中不能使用变量跟踪计算的状态,所以我们需要研究如何使用不可变对象,比如可以使用元组和命名元组构建复杂的不可变数据结构。

不可变对象的概念在Python中并不陌生。程序使用不可变元组比使用可变对象的性能要好。在某些情况下,使用不可变对象时,我们需要重新考虑算法,以避免改变对象所带来的开销。

我们将(几乎)完全避免使用类定义,虽然在一门面向对象编程的语言里这么做似乎不合逻辑。通过阅读本书你会了解,函数式编程并不需要有状态的对象。可以定义可调用对象,并通过它们把互相关联的函数放在同一个命名空间内,这类对象可以在多个级别上进行配置。通过可调用对象创建缓存也很简单,而且能大幅提升性能。

下面介绍一个处理不可变对象的常用设计模式:wrapper()函数。由元组组成的列表是常见的数据结构,我们经常用以下两种方式处理它们。

  • 使用高阶函数:如前所述,为max()提供一个lambda表达式——max(year_cheese, key=lambda yc: yc[1])

  • 使用“打包-处理-拆包”模式:在函数式语境中,这种模式可以表述为unwrap(process (wrap(structure)))

例如,看看以下命令片断。

>>> max(map(lambda yc: (yc[1], yc), year_cheese))[1]
(2007, 33.5)

这个例子很好地展示了上面说的三部曲模式:打包数据结构,获取打包后数据结构的最大值,然后拆包。

首先是打包。map(lambda yc: (yc[1],yc), year_cheese)把列表中的每一项转换成一个二元组,其中用于比较的项后面跟着原始项,这里用于比较的项是yc[1]

接下来用max()函数处理逻辑。因为之前已经把需要比较的项变成了二元组的第一个元素,所以使用max()的默认方式就可以了,不再需要它的高阶函数能力。

最后用下标[1]提取最终结果,即拆包。这里是从max()返回的结果中通过取第二个元素得到目标元组。

这类打包、拆包的操作在函数式编程中很常用,所以有些函数式语言为这类操作提供了专门的函数,例如fst()snd()等,这样就可以使用前缀式语法,而不必使用[0][1]这样的下标了。我们可以实现这些函数,并将其应用于“打包-处理-拆包”模式中,如下所示。

>>> snd = lambda x: x[1]
>>> snd(max(map(lambda yc: (yc[1], yc), year_cheese)))
(2007, 33.5)

上例中,通过定义snd()函数实现取元组第二个元素的功能,这样实现的“打包-处理-拆包”模式更易读。我们使用map(lambda... , year_cheese)打包原始数据项,使用max()进行处理,最后用snd()函数从返回的元组中提取第二个元素。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程