Python 生成器表达式

下面介绍如何使用复杂的生成器表达式转换数据类型,以及如何把复杂函数应用于生成器创建的单个值。

这些非生成器函数是“标量的”,因为它们处理的是单个标量值。为了处理集合数据,需要把标量函数嵌入生成器表达式中。

继续前面的例子,首先创建haversine函数,然后使用生成器表达式将标量的haversine函数应用于从KML文件中提取的数值。
haversine函数的具体实现如下:

from math import radians, sin, cos, sqrt, asin
from typing import Tuple
MI = 3959
NM = 3440
KM = 6371
Point = Tuple[float, float]
def haversine(p1: Point, p2: Point, R: float=NM) -> float:
    lat_1, lon_1 = p1
    lat_2, lon_2 = p2
    Δ_lat = radians(lat_2 - lat_1)
    Δ_lon = radians(lon_2 - lon_1)
    lat_1 = radians(lat_1)
    lat_2 = radians(lat_2)
    a = sqrt(
        sin(Δ_lat / 2) ** 2 +
        cos(lat_1) * cos(lat_2) * sin(Δ_lon / 2) ** 2
    )
    c = 2 * asin(a)
    return R * c

这个实现比较简单,在网上搜索一下,找到代码并复制过来即可。这里给起点、终点和返回值添加了类型标示,显式类型声明Point = Tuple[float, float]使得mypy工具可以正确地使用函数。

下面的代码演示了如何使用前面定义好的函数处理KML文件中的数据,并计算出距离序列:

trip = (
    (start, end, round(haversine(start, end), 4))
    for start, end in
        legs(float_from_pair(lat_lon_kml()))
)

for start, end, dist in trip:
    print(start, end, dist)

关键部分是赋给trip变量的生成器表达式。我们用起点、终点以及两点间的距离组成三元组,其中起点和终点来自legs()函数,用它来处理从KML文件中提取的经纬度数值对转换而来的浮点数据。

计算结果如下所示:

(37.54901619777347, -76.33029518659048) (37.840832, -76.273834) 17.7246
(37.840832, -76.273834) (38.331501, -76.459503) 30.7382
(38.331501, -76.459503) (38.845501, -76.537331) 31.0756
(36.843334, -76.298668) (37.549, -76.331169) 42.3962
(37.549, -76.331169) (38.330166, -76.458504) 47.2866
(38.330166, -76.458504) (38.976334, -76.473503) 38.8019

这样就简洁地定义了每个处理步骤。整个处理过程由函数和生成器表达式组成,总体而言也很简洁。

当然,这里得到的输出数据还需要进一步处理,比如首先需要用字符串的format()方法把输出数据整理得易读一些。

更重要的是,需要从数据中提取一些累积值,即对已有数据进行归约。比如可以提取数据的最大纬度值和最小纬度值,从而得到一条路线的最南点和最北点。或者通过归约数据,找到路径段中最长的距离,或者所有距离的和。

使用Python处理数据时有个问题:trip变量只能使用一次,无法对其进行多次归约,而itertools.tee()函数能够多次使用可迭代对象,毕竟每次归约都要重新读取并解析KML文件,成本太高了。

将中间计算结果实例化可以提高计算效率,稍后详述并介绍如何对已有数据进行多次归约。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程