Python 打包多项数据并映射,当使用类似于((f(x), x) for x in C)
这样的结构时,首先将多个值打包以创建元组,然后进行映射。通常用这种方法保存中间计算结果。它既可以避免使用包含复杂状态的对象,也可以避免重复计算。
下面是根据路径点创建旅行数据的计算过程的一部分,代码如下所示:
from ch02_ex3 import (
float_from_pair, lat_lon_kml, limits, haversine, legs
)
path = float_from_pair(float_lat_lon(row_iter_kml(source)))
trip = tuple(
(start, end, round(haversine(start, end), 4))
for start, end in legs(iter(path))
)
对上述代码稍做修改,创建一个高阶函数把打包部分与其他函数分开,具体实现如下:
from typing import Callable, Iterable, Tuple, Iterator
Point = Tuple[float, float]
Leg_Raw = Tuple[Point, Point]
Point_Func = Callable[[Point, Point], float]
Leg_D = Tuple[Point, Point, float]
def cons_distance(
distance: Point_Func,
legs_iter: Iterable[Leg_Raw]) -> Iterator[Leg_D]:
return (
(start, end, round(distance(start,end), 4))
for start,end in legs_iter
)
这个函数将每个路径段拆解开,保存在start
和end
两个变量里,这些变量是类型Point
的实例,也就是由浮点数组成的二元组。这些变量作为distance()
函数的参数,计算出每段距离。距离函数接收两个Point
类型对象作参数,返回一个float
值。cons_distance()
返回一个三元组,包括原始数据中的起点和终点,以及距离计算结果。
接下来修改trip
的赋值表达式,通过haversine()
函数计算距离,如下所示:
path = float_from_pair(float_lat_lon(row_iter_kml(source)))
trip2 = tuple(cons_distance(haversine, legs(iter(path))))</code></pre>
用高阶函数cons_distance()
代替了生成器表达式,使用函数作为参数,返回生成器表达式。
对上面的函数稍做修改,得到如下函数:
from typing import Callable, Iterable, Tuple, Iterator, Any
Point = Tuple[float, float]
Leg_Raw = Tuple[Point, Point]
Point_Func = Callable[[Point, Point], float]
Leg_P_D = Tuple[Leg_Raw, ...]
def cons_distance3(
distance: Point_Func,
legs_iter: Iterable[Leg_Raw]) -> Iterator[Leg_P_D]:
return (
leg + (round(distance(*leg), 4), ) # 1-tuple
for leg in legs_iter
)
该版本清晰地展示了如何基于原有对象创建新的对象,遍历旅行数据中的每个路径段,类型为Leg_Raw
,即包含两个点的二元组,沿着路径段计算距离,把代表原始路径段的Leg_Raw
类型的对象与计算得到的距离组合在一起。
由于这些cons_distance()
函数都接收函数作为参数,因此可以用其他公式计算距离。例如,可以使用math.hypot(lat(start) - lat(end), lon(start) - lon(end))
计算出每个路径段起点和终点间的平面距离,尽管这种算法不太合适在这里使用。
后面将使用partial()
函数设置haversine()
函数中R
参数的值来改变距离计算单位。