Python 拆包和映射数据

Python 拆包和映射数据,当使用类似于(f(x) for x, y in C)这样的结构时,我们使用for语句中的多重赋值拆开一个元组,并将一个函数应用于其中一部分数据。整体上这是一个映射。这是Python常用的改变结构和应用函数的优化方法。
继续使用第4章中的旅行数据。下面是一个拆包并映射的具体实现。

from typing import Callable, Iterable, Tuple, Iterator, Any

Conv_F = Callable[[float], float]
Leg = Tuple[Any, Any, float]

def convert(
        conversion: Conv_F,
        trip: Iterable[Leg]) -> Iterator[float]:
    return (
        conversion(distance) for start, end, distance in trip
    )

该高阶函数使用下面的转换函数处理原始数据。

to_miles = lambda nm: nm * 5280 / 6076.12
to_km = lambda nm: nm * 1.852
to_nm = lambda nm: nm

有了转换函数,就可以提取距离数据,再进行转换了,如下所示:

convert(to_miles, trip)

处理结果是一系列浮点数,如下所示:

[20.397120559090908, 35.37291511060606, ..., 44.652462240151515]

convert()函数的for语句不难看出,这个函数只适用于“起点-终点-距离”格式的旅行数据。

可以进一步抽象这类“拆包-映射”设计模式,整个过程稍复杂。首先需要定义通用分解函数,如下所示:

fst = lambda x: x[0]
snd = lambda x: x[1]
sel2 = lambda x: x[2]

要表达f(sel2(s_e_d)) for s_e_d in trip,就要用到复合函数。我们把一个类似于to_miles()的函数和一个类似于sel2()的选择器组合在一起。在Python中,可以用匿名函数把函数组合在一起,如下所示:

to_miles = lambda s_e_d: to_miles(sel2(s_e_d))

这样就得到了一个更长,但更通用的实现,如下所示:

(to_miles(s_e_d) for s_e_d in trip)

这个版本更具通用性,不过用处似乎不太大。

对于上述convert()高阶函数,需要特别注意的是,它使用函数作为参数,并返回生成器函数作为结果。convert()函数不是生成器函数,不会生成任何值,它的返回值是一个生成器表达式,需要对其求值才能得到具体的计算结果。我们使用Iterator[float]来强调返回结果是迭代器,也就是
Python生成器函数的子类。

在这个设计模式中,可以用多重过滤代替映射,实现方法是在返回的生成器表达式中,用if从句实现过滤功能。

映射和过滤结合可以生成更复杂的函数。创建复杂的函数来缩短处理过程似乎是个好主意,但实际情况并非总是如此。复杂函数的性能往往不如嵌套的map()函数和filter()函数。总体而言,只有在函数通过封装概念来降低软件开发复杂度的情况下,才考虑使用复杂函数。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程