什么时候可以使用“星图"而不是“列表理解"? [英] When`starmap` could be preferred over `List Comprehension`

查看:91
本文介绍了什么时候可以使用“星图"而不是“列表理解"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在回答问题时笨拙计算递增的一组数字之间的差异,是否有更漂亮的方法?,我提出了两种解决方案,一种使用List Comprehension,另一种使用

While answering the question Clunky calculation of differences between an incrementing set of numbers, is there a more beautiful way?, I came up with two solutions, one with List Comprehension and other using itertools.starmap.

对我来说,list comprehension语法看起来更清晰,易读,更冗长,并且更具Python风格.但是由于 starmap 在itertools中很好用,我当时想知道,一定有原因.

To me, list comprehension Syntax looks more lucid, readable, less verbose and more Pythonic. But still as starmap is well available in itertools, I was wondering, there has to be a reason for it.

我的问题是,何时starmapList Comprehension更可取?

My Question is whenstarmap could be preferred over List Comprehension?

注意如果是样式问题,则肯定与There should be one-- and preferably only one --obvious way to do it.

Note If its a matter of Style then it definitely contradicts There should be one-- and preferably only one --obvious way to do it.

头对头比较

可读性计数.--LC

这又是一个感知问题,但是对我来说LCstarmap更具可读性. 要使用starmap,您需要导入operator或定义lambda或某些显式的multi-variable函数,但是仍然需要从itertools导入.

Its again a matter of perception but to me LC is more readable than starmap. To use starmap, either you need to import operator, or define lambda or some explicit multi-variable function and nevertheless extra import from itertools.

性能 --- LC

>>> def using_star_map(nums):
    delta=starmap(sub,izip(nums[1:],nums))
    return sum(delta)/float(len(nums)-1)
>>> def using_LC(nums):
    delta=(x-y for x,y in izip(nums[1:],nums))
    return sum(delta)/float(len(nums)-1)
>>> nums=[random.randint(1,10) for _ in range(100000)]
>>> t1=Timer(stmt='using_star_map(nums)',setup='from __main__ import nums,using_star_map;from itertools import starmap,izip')
>>> t2=Timer(stmt='using_LC(nums)',setup='from __main__ import nums,using_LC;from itertools import izip')
>>> print "%.2f usec/pass" % (1000000 * t1.timeit(number=1000)/100000)
235.03 usec/pass
>>> print "%.2f usec/pass" % (1000000 * t2.timeit(number=1000)/100000)
181.87 usec/pass

推荐答案

我通常看到的区别是map()/starmap()最适合您实际上只是在列表中的每个项目上调用函数的地方.在这种情况下,它们会更清晰一些:

The difference I normally see is map()/starmap() are most appropriate where you are literally just calling a function on every item in a list. In this case, they are a little clearer:

(f(x) for x in y)
map(f, y) # itertools.imap(f, y) in 2.x

(f(*x) for x in y)
starmap(f, y)

一旦开始需要同时放入lambdafilter,则应切换到列表comp/generator表达式,但是如果是单个函数,则语法对于列表理解的生成器表达式.

As soon as you start needing to throw in lambda or filter as well, you should switch up to the list comp/generator expression, but in cases where it's a single function, the syntax feels very verbose for a generator expression of list comprehension.

它们 是可互换的,并且在有疑问的情况下,请坚持使用生成器表达式,因为它通常更具可读性,但在简单情况下(map(int, strings)starmap(Vector, points))使用map()/starmap()有时可以使事情更容易阅读.

They are interchangeable, and where in doubt, stick to the generator expression as it's more readable in general, but in a simple case (map(int, strings), starmap(Vector, points)) using map()/starmap() can sometimes make things easier to read.

我认为starmap()更具可读性的示例:

An example where I think starmap() is more readable:

from collections import namedtuple
from itertools import starmap

points = [(10, 20), (20, 10), (0, 0), (20, 20)]

Vector = namedtuple("Vector", ["x", "y"])

for vector in (Vector(*point) for point in points):
    ...

for vector in starmap(Vector, points):
    ...

对于map():

values = ["10", "20", "0"]

for number in (int(x) for x in values):
    ...

for number in map(int, values):
    ...

性能:

python -m timeit -s "from itertools import starmap" -s "from operator import sub" -s "numbers = zip(range(100000), range(100000))" "sum(starmap(sub, numbers))"                         
1000000 loops, best of 3: 0.258 usec per loop

python -m timeit -s "numbers = zip(range(100000), range(100000))" "sum(x-y for x, y in numbers)"                          
1000000 loops, best of 3: 0.446 usec per loop

用于构造namedtuple:

python -m timeit -s "from itertools import starmap" -s "from collections import namedtuple" -s "numbers = zip(range(100000), reversed(range(100000)))" -s "Vector = namedtuple('Vector', ['x', 'y'])" "list(starmap(Vector, numbers))"
1000000 loops, best of 3: 0.98 usec per loop

python -m timeit -s "from collections import namedtuple" -s "numbers = zip(range(100000), reversed(range(100000)))" -s "Vector = namedtuple('Vector', ['x', 'y'])" "[Vector(*pos) for pos in numbers]"
1000000 loops, best of 3: 0.375 usec per loop

在我的测试中,我们正在谈论使用简单函数(没有lambda),starmap()比等效的生成器表达式要快.自然,除非是公认的瓶颈,否则性能应该在可读性上倒退.

In my tests, where we are talking about using simple functions (no lambda), starmap() is faster than the equivalent generator expression. Naturally, performance should take a back-seat to readability unless it's a proven bottleneck.

lambda如何杀死任何性能提升的示例,与第一组示例相同,但使用lambda而不是operator.sub():

Example of how lambda kills any performance gain, same example as in the first set, but with lambda instead of operator.sub():

python -m timeit -s "from itertools import starmap" -s "numbers = zip(range(100000), range(100000))" "sum(starmap(lambda x, y: x-y, numbers))" 
1000000 loops, best of 3: 0.546 usec per loop

这篇关于什么时候可以使用“星图"而不是“列表理解"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆