python operator模块
在函数式编程中,经常需要把算术运算符当作函数使用。例如,不使用递归计算阶乘。求 和可以使用sum
函数,但是求积则没有这样的函数。我们可以使用reduce
函数,但是需要一个函数计算序列中两个元素之积。如下展示如何使用 lambda
表达式解决这个问题。
from functools import reduce
def fact(n):
return reduce(lambda a, b: a*b, range(1, n+1))
operator 模块为多个算术运算符提供了对应的函数,从而避免编写 lambda a, b: a*b 这种 平凡的匿名函数。使用算术运算符函数,可以把示例进行改写。
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 上的元 素。
from operator import 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))
]
for city in sorted(metro_data, key=itemgetter(1)):
print(city)
如果把多个参数传给 itemgetter
,它构建的函数会返回提取的值构成的元组:
from operator import 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))
]
cc_name = itemgetter(1, 0)
for city in metro_data:
print(cc_name(city))
itemgetter
使用 []
运算符,因此它不仅支持序列,还支持映射和任何实现 __getitem__
方 法的类。
attrgetter
与 itemgetter
作用类似,它创建的函数根据名称提取对象的属性。如果把 多个属性名传给 attrgetter
,它也会返回提取的值构成的元组。此外,如果参数名中包 含 .
(点号),attrgetter
会深入嵌套对象,获取指定的属性。这些行为如下示例 所示。 这个控制台会话不短,因为我们要构建一个嵌套结构,这样才能展示 attrgetter
如何处理 包含点号的属性名。
from collections import namedtuple
from operator import attrgetter
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))
]
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]
print(metro_areas[0])
print(metro_areas[0].coord.lat)
name_lat = attrgetter('name', 'coord.lat')
for city in sorted(metro_areas, key=attrgetter('coord.lat')):
print(name_lat(city))
下面是 operator
模块中定义的部分函数(省略了以 _ 开头的名称,因为它们基本上是实现 细节)
s = [name for name in dir(operator) if not name.startswith('_')]
print(a)
# 结果:
['abs', 'add', 'and_', 'attrgetter', 'concat', 'contains', 'countOf', 'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd', 'iand', 'iconcat', 'ifloordiv', 'ilshift', 'imod', 'imul', 'index', 'indexOf', 'inv', 'invert', 'ior', 'ipow', 'irshift', 'is_', 'is_not', 'isub', 'itemgetter', 'itruediv', 'ixor', 'le', 'length_hint', 'lshift', 'lt', 'methodcaller', 'mod', 'mul', 'ne', 'neg', 'not_', 'or_', 'pos', 'pow', 'rshift', 'setitem', 'sub', 'truediv', 'truth', 'xor']
这 52 个名称中大部分的作用不言而喻。以 i 开头、后面是另一个运算符的那些名称(如 iadd
、iand
等),对应的是增量赋值运算符(如 +=、&= 等)。如果第一个参数是可变的,那 么这些运算符函数会就地修改它;否则,作用与不带 i 的函数一样,直接返回运算结果。
在 operator
模块余下的函数中,我们最后介绍一下 methodcaller
。它的作用与 attrgetter
和 itemgetter
类似,它会自行创建函数。methodcaller
创建的函数会在对象上调用参数指 定的方法,如下示例 :
"""
operator 中 methodcaller
它的作用与 attrgetter 和 itemgetter 类似,它会自行创建函数。
methodcaller 创建的函数会在对象上调用参数指 定的方法,
"""
from operator import methodcaller
s = 'The time has come'
upcase = methodcaller('upper')
print(upcase(s))
hiphenate = methodcaller('replace', ' ', '-')
print(hiphenate(s))
示例中的第一个测试只是为了展示 methodcaller
的用法,如果想把 str.upper
作为函 数使用,只需在 str
类上调用,并传入一个字符串参数,如下所示:
print(str.upper(s))
示例中的第二个测试表明,methodcaller
还可以冻结某些参数,也就是部分应用 (partial application
),这与 functools.partial
函数的作用类似。
functools
模块提供了一系列高阶函数,其中最为人熟知的或许是 reduce
,余下的函数中,最有用的是 partial
及其变体,partialmethod
。
functools.partial
这个高阶函数用于部分应用一个函数。部分应用是指,基于一个函数创 建一个新的可调用对象,把原函数的某些参数固定。使用这个函数可以把接受一个或多个 参数的函数改编成需要回调的 API,这样参数更少。下面示例做了简单的演示。
使用 partial 把一个两参数函数改编成需要单参数的可调用对象
from operator import mul
from functools import partial
# 使用 mul 创建 triple 函数,把第一个定位参数定为 3。
triple = partial(mul, 3)
print(triple(7))
# 21
print(list(map(triple, range(1, 10))))
# [3, 6, 9, 12, 15, 18, 21, 24, 27]
如果处理 多国语言编写的文本,在比较或排序之前可能会想使用 unicode.normalize('NFC', s)
处理 所有字符串 s
。如果经常这么做,可以定义一个 nfc
函数,如示例 所示。
使用 partial 构建一个便利的 Unicode 规范化函数
import unicodedata, functools
nfc = functools.partial(unicodedata.normalize, 'NFC')
s1 = 'café'
s2 = 'cafe\u0301'
print(s1, s2)
# ('café', 'café')
s1 == s2
# False
nfc(s1) == nfc(s2)
# True
partial 的第一个参数是一个可调用对象,后面跟着任意个要绑定的定位参数和关键字参数。
使用 partial,冻结一个定位参数和一个关键字 参数。
from functools import partial
def tag(name, *content, cls=None, **attrs):
"""生成一个或多个HTML标签"""
if cls is not None:
attrs['class'] = cls
if attrs:
attr_str = ''.join(' %s="%s"' % (attr, value) for attr, value in sorted(attrs.items()))
else:
attr_str = ''
if content:
return '\n'.join('<%s%s>%s</%s>' % (name, attr_str, c, name) for c in content)
else:
return '<%s%s />' % (name, attr_str)
# 冻结
picture = partial(tag, 'img', cls='pic-frame')
下一篇: 利用Java截取图片例子