Python 中支持函数式编程的 operator 与 functools 包
引言
尽管 Python 之父 Guido 表明 Python 的目标并非成为函数式编程语言,但借助operator和functools等包,我们能轻松实现函数式编程风格。本文将详细介绍这两个包。
operator 模块
算术运算符函数
在函数式编程里,常需把算术运算符当作函数使用。例如计算阶乘,使用reduce函数时,若不使用operator模块,需用lambda表达式
lambda a, b: a*b
来计算序列元素之积;而使用operator.mul可避免编写此类平凡的匿名函数。
from functools import reduce
from operator import mul def fact(n): return reduce(mul, range(1, n + 1))
itemgetter 函数
itemgetter能替代从序列中取出元素的lambda表达式。它会自行构建函数,用于提取集合中指定索引位置的元素。例如,可根据元组的某个字段对元组列表排序。
metro_data = [ ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)), ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)), ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)), ('New York - Newark', 'US', 20.104, (40.808611, -74.020386)), ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
]
from operator import itemgetter
for city in sorted(metro_data, key=itemgetter(1)): print(city)
若传入多个参数,itemgetter构建的函数会返回提取值构成的元组,且它支持序列、映射及任何实现__getitem__方法的类。
attrgetter 函数
attrgetter与itemgetter类似,它创建的函数根据名称提取对象的属性。传入多个属性名时,也会返回提取值构成的元组。若参数名包含.点号,它会深入嵌套对象获取指定属性。
from collections import namedtuple
LatLong = namedtuple('LatLong', 'lat long')
Metropolis = namedtuple('Metropolis', 'name cc pop coord')
metro_areas = [Metropolis(name, cc, pop, LatLong(lat, long)) for name, cc, pop, (lat, long) in metro_data]
from operator import attrgetter
name_lat = attrgetter('name', 'coord.lat')
for city in sorted(metro_areas, key=attrgetter('coord.lat')): print(name_lat(city))
methodcaller 函数
methodcaller会自行创建函数,该函数会在对象上调用参数指定的方法,还可冻结某些参数,实现部分应用。
from operator import methodcaller s = 'The time has come' upcase = methodcaller('upper')
print(upcase(s))
使用 functools.partial 冻结参数
partial 函数简介
functools.partial是一个高阶函数,用于部分应用一个函数,即基于一个函数创建新的可调用对象,固定原函数的某些参数,使接受多个参数的函数改编成适用于回调 API 的少参数函数。
from operator import mul
from functools import partial
triple = partial(mul, 3)
print(triple(7))
print(list(map(triple, range(1, 10))))
实际应用示例
在处理多国语言文本时,可使用partial构建便利的 Unicode 规范化函数。
import unicodedata, functools
nfc = functools.partial(unicodedata.normalize, 'NFC')
s1 = 'café'
s2 = 'cafe\u0301'
print(nfc(s1) == nfc(s2))
应用于自定义函数
还可将partial应用到自定义函数上,冻结定位参数和关键字参数。
from tagger import tag
from functools import partial
picture = partial(tag, 'img', cls='pic - frame')
print(picture(src='wumpus.jpeg'))
partialmethod 函数
functools.partialmethod函数(Python 3.4 新增)作用与partial类似,不过是用于处理方法的。
lru_cache 函数
functools模块中的lru_cache函数会做备忘(memoization),存储耗时函数的调用结果,避免重新计算。
总之,operator和functools包为 Python 实现函数式编程提供了强大的支持,合理运用这些工具能让代码更加简洁高效。