Python 可迭代对象,在Python中处理集合时,经常使用for
循环语句。当处理实例化了的集合数据(例如元组、列表、映射与set)时,for
循环中包含了显式的状态管理。虽然这种用法不符合函数式编程的原则,但反映出它是Python的一种必要的优化手段。如果能保证状态管理只用于for
语句对应的迭代器对象,就可以在不过分偏离纯粹的函数式编程原则的前提下利用这一语言特性。如果在for
循环体外部使用循环变量,就背离了函数式编程的原则。
for
循环迭代处理常用于unwrap(process(wrap(iterable)))
设计模式。wrap()
函数将原始可迭代对象中的每个元素转换为一个二元组,其中第一个元素是用于排序的键或者其他数值,第二个元素是原来不可变的输入数据。接着基于前面打包的结果处理数据。最后使用unwrap()
函数拆分处理后的元组,舍弃打包数值,保留处理结果。
在函数式语境下上述操作十分频繁,因此定义如下两个函数:
fst = lambda x: x[0]
snd = lambda x: x[1]
这两个函数从元组中分别取出第一个元素和第二个元素,在process()
函数和unwrap()
函数中经常用到。
另一个常用的模式是wrap3(wrap2(wrap1()))
。这种情况下,我们从简单的元组开始,加入后续计算结果,打包成新的元组,从而形成更大也更复杂的元组。该设计模式的一个变体是基于源对象创建新的、更复杂的命名元组实例。这两种模式都属于生长设计模式。
生长设计模式的一个应用是处理经纬度数值。处理过程的第一步是将路径上的点(lat, lon)
转换为路径段(begin, end)
,计算结果表示为:((lat, lon), (lat, lon))
。对集合中的每个元素,用fst(item)
获取起点值,用snd(item)
获取终点值。
稍后演示如何创建一个生成器函数遍历输入文件中的数据,将后面需要处理的原始数据保存到可迭代对象中。
获得原始数据后,将演示如何计算某段路径的半正矢距离。经wrap(wrap(iterable()))
处理后,数据变成一个三元组序列:((lat, lon), (lat, lon), distance)
,这样就可以计算最长距离、最短距离、外接矩形及其他数据汇总值了。