python 函数式编程包_fluent python 5.10节 支持函数式编程的包

虽然 Guido 明确表明,Python的目标不是变成函数式编程语言,但是得 益于 operator 和 functools 等包的支持,函数式编程风格也可以信手拈来。接下来的两节分别介绍这两个包。

5.10.1 operator模块

在函数式编程中,经常需要把算术运算符当作函数使用。例如,不使用 递归计算阶乘。求和可以使用 sum 函数,但是求积则没有这样的函数。 我们可以使用 reduce 函数,但是需要一个函数 计算序列中两个元素之积。

使用 reduce 函数和一个匿名函数计算阶乘

from functools import reduce

def fact(n):

return reduce(lambda a, b: a*b, range(1, n+1))

operator 模块为多个算术运算符提供了对应的函数,从而避免编写 lambda a, b: a*b 这种平凡的匿名函数。

使用 reduce 和 operator.mul 函数计算阶乘

from functools import reduce

from operator import mul

def fact(n):

return reduce(mul, range(1, n+1))

operator 模块中还有一类函数,能替代从序列中取出元素或读取对象属性的 lambda 表达式:因此,itemgetter 和 attrgetter 其实会自行构建函数。

下面的例子展示了 itemgetter 的常见用途:根据元组的某个字段给元组列表排序。在这个示例中,按照国家代码(第 2 个字段)的顺序打印 各个城市的信息。其实,itemgetter(1) 的作用与 lambda fields: fields[1] 一样:创建一个接受集合的函数,返回索引位 1 上的元素。

演示使用 itemgetter 排序一个元组列表

>>> 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)

...

('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833))

('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889))

('Tokyo', 'JP', 36.933, (35.689722, 139.691667))

('Mexico City', 'MX', 20.142, (19.433333, -99.133333))

('New York-Newark', 'US', 20.104, (40.808611, -74.020386))

>>> for city in sorted(metro_data, key=itemgetter(0)):

... print(city)

...

('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))

('Tokyo', 'JP', 36.933, (35.689722, 139.691667))

>>>

如果把多个参数传给itemgetter,它构建的函数会返回提取的值构成的元组:

>>> cc_name = itemgetter(1, 0)

>>> for city in metro_data:

... print(cc_name(city))

...

('JP', 'Tokyo')

('IN', 'Delhi NCR')

('MX', 'Mexico City')

('US', 'New York-Newark')

('BR', 'Sao Paulo')

>>>

itemgetter 使用 [] 运算符,因此它不仅支持序列,还支持映射和任 何实现 __getitem__ 方法的类。

attrgetter 与 itemgetter 作用类似,它创建的函数根据名称提取对象的属性。如果把多个属性名传给 attrgetter,它也会返回提取的值构成的元组。此外,如果参数名中包含 .(点号),attrgetter 会深 入嵌套对象,获取指定的属性。

>>> 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]

>>> metro_areas[0]

Metropolis(name='Tokyo', cc='JP', pop=36.933, coord=LatLong(lat=35.689722, long=139.691667))

>>> metro_areas[0].coord.lat

35.689722

>>> from operator import attrgetter

# 定义一个 attrgetter,获取 name 属性和嵌套的 coord.lat 属性。

>>> name_lat = attrgetter('name', 'coord.lat')

>>> for city in sorted(metro_areas, key=attrgetter('coord.lat')):

... print(name_lat(city))

...

('Sao Paulo', -23.547778)

('Mexico City', 19.433333)

('Delhi NCR', 28.613889)

('Tokyo', 35.689722)

('New York-Newark', 40.808611)

>>>

在 operator 模块余下的函数中,我们最后介绍一下 methodcaller。 它的作用与 attrgetter 和 itemgetter 类似,它会自行创建函数。methodcaller创建的函数会在对象上调用参数指定的方法。

>>> from operator import methodcaller

>>> s = 'the time has come'

>>> upcase = methodcaller('upper')

>>> upcase(s)

'THE TIME HAS COME'

>>> hiphenate = methodcaller('replace', ' ', '-')

>>> hiphenate(s)

'the-time-has-come'

>>>

第二个测试表明,methodcaller 还可以冻结某些参数, 也就是部分应用(partial application),这与 functools.partial 函数 的作用类似。详情参见下一节。

5.10.2 使用functools.partial冻结参数

functools 模块提供了一系列高阶函数,其中最为人熟知的或许是 reduce。余下的函数中,最有用的是 partial 及其变体,partialmethod。

functools.partial这个高阶函数用于部分应用一个函数。部分应用 是指,基于一个函数创建一个新的可调用对象,把原函数的某些参数固定。使用这个函数可以把接受一个或多个参数的函数改编成需要回调的 API,这样参数更少。

使用 partial 把一个两参数函数改编成需要单参数的 可调用对象

>>> from operator import mul

>>> from functools import partial

>>> triple = partial(mul, 3)

>>> triple(7)

21

>>> list(map(triple, range(1, 10)))

[3, 6, 9, 12, 15, 18, 21, 24, 27]

>>>

partial 的第一个参数是一个可调用对象,后面跟着任意个要绑定的定位参数和关键字参数。

functools.partialmethod 函数(Python 3.4 新增)的作用与 partial 一样,不过是用于处理方法的。

functools 模块中的 lru_cache函数令人印象深刻,它会做备忘(memoization),这是一种自动优化措施,它会存储耗时的函数调用结 果,避免重新计算。第 7 章将会介绍这个函数,还将讨论装饰器,以及 旨在用作装饰器的其他高阶函数:singledispatch 和 wraps。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值