Python 运算符的星号映射,函数itertools.starmap()
是高阶函数map()
的一个变体。函数map()
会将某个函数应用于序列中的每一项。函数starmap(f, S)
则假定序列S
中的每一项i
都是一个元组,并且使用f(*i)
作为映射。每个元组中数据项的个数必须与给定函数中的参数个数相匹配。
示例如下:
>>> d = starmap(pow, zip_longest([], range(4), fillvalue=60))
函数itertools.zip_longest()
会创建如下一组序列对:
[(60, 0), (60, 1), (60, 2), (60, 3)]
该函数之所以会得到此结果是因为我们提供了两个序列:方括号[]
和参数range(4)
。当较短序列中的数据处理完后,会使用fillvalue
参数。
当使用starmap()
函数时,每一个元组对都会作为给定函数的参数。本例中使用的是operator.pow()
函数,即**
运算符。该表达式计算了[60**0, 60**1, 60**2, 60**3]
的值。变量d
的值是[1, 60, 3600, 216000]
。
函数starmap()
接收元组序列。map(f, x, y)
函数和starmap(f, zip(x, y))
函数大致等同。
上述示例中itertools.starmap()
函数的延续如下所示:
>>> p = (3, 8, 29, 44)
>>> pi = sum(starmap(truediv, zip(p, d)))
上面打包了分别含4个值的两个序列。变量d
的值由上述的starmap()
计算得到,变量p
代表一个简单的文本项列表,我们将这两个变量打包成对。starmap()
函数与operator.truediv()
函数配合使用,后者即/
运算符。
这样就能对一组分数序列进行求和了,其结果约为:
一个更简化的版本如下所示,它使用了map(f, x, y)
函数代替starmap(f, zip(x,y))
函数。
>>> pi = sum(map(truediv, p, d))
>>> pi
3.1415925925925925
在本例中,基数为60的分数转换为了基数为10的分数。变量d
中的值序列会作为合适的分母。也可以用类似于前面介绍的技术来转换其他基数。
有些近似可能涉及无穷项的求和(或乘积)。可以用类似于前面介绍的技术对其进行求值。可以利用itertools
模块中的count()
函数来近似生成任意数量的项。随后可以使用takewhile()
函数只累计那些有助于提高解的精确度的值。从另一个角度来看,takewhile()
生成了一个显著值的数据流,并且会在遇到非显著值的时候停止处理。
计算一个潜在无穷序列之和的示例如下:
>>> from itertools import count, takewhile
>>> num = map(fact, count())
>>> den = map(semifact, (2*n+1 for n in count()))
>>> terms = takewhile(
... lambda t: t > 1E-10, map(truediv, num, den))
>>> 2*sum(terms)
3.1415926533011587
变量num
是一个潜在的无穷分子序列,且它基于前面示例中定义的阶乘函数。函数count()
返回升序的值,即从零开始无限递增。变量den
是一个潜在的无穷分母序列,且它基于半阶乘函数。前面的示例中定义过这个函数,它也使用count()
来创建一个潜在的无穷值序列。
通过map()
函数将operators.truediv()
函数(即/
运算符)应用于每一对值来创建数据项。将其封装在takewhile()
函数中,以便只在数据值大于某个相对较小的值时(本例中为 10^{-10}),才从map()
的输出中提取该项数据。
该定义的级数展开式如下所示:
这个级数展开式的一个有趣的变体是将operator.truediv()
函数替换为fractions.Fraction()
函数,这会创建不受浮点数近似限制的精确有理值。
可以使用operators
模块中的所有Python内置运算符,其中包括所有位处理运算符以及比较运算符。在某些情况下,相比形式复杂的用函数表示运算符的starmap()
函数,生成器表达式更为简洁明了。
模块operator
的作用是简化匿名函数。可以使用operator.add
方法代替add=lambda a, b: a+b
方法。如果表达式比单个运算符复杂,那么唯一的方法便是编写匿名函数。