问题实际上是标题所说的。
问题的原因:
map
func比下面代码中的for
循环慢
是因为我的代码中存在某些问题,还是还有其他问题?
代码:
import timeit
setup = '''
def translate(x):
x[1]+=1
x[2]+=1
x[3]+=1
atoms = [[1,1,1,1]]*1000
'''
smt1 = '''for i in atoms: translate(i)'''
smt2 = '''map(translate, atoms)'''
time_for = timeit.Timer(setup=setup, stmt=smt1)
time_map = timeit.Timer(setup=setup, stmt=smt2)
print time_for.timeit(10000)
print time_map.timeit(10000)
输出(Windows 7(64位)I-3 2nd gen):
>>>
3.4691164256
3.5064888507
输出(Windows 7(32位)core2duo):
>>>
5.58571625252
6.25803459664
我想我应该提到我使用的是Python 2.7.3,所以尽管Python 3中的map
是一个生成器,但在Python 2中却不是这样,所以这个“问题”无法复制到Python 3。
更新
为了解决那些说原子应该是不可变的,这里有一个不同版本的设置(它更慢,但仍然显示差异):
setup = '''
def translate(x):
return tuple(i+1 for i in x)
atoms = [(1,1,1,1)]*1000
'''
输出(Windows 7(32位)core2duo):
>>>
31.0213507144
29.7194933508
答案 0 :(得分:5)
这是因为map
创建了一个新结构,而for
只修改了当前结构。
答案 1 :(得分:4)
一些观察结果。
[[1,1,1,1]]*n
是个坏主意。这会创建对{em>相同列表的n
个引用。 [None]*n
虽然None
是不可变的,但这样做很好。import timeit
setup = '''
def translate(x):
x[1]+=1
x[2]+=1
x[3]+=1
atoms = [[1,1,1,1] for _ in range(1000) ]
'''
smt1 = '''lst = []
for i in atoms: lst.append(translate(i))'''
smt2 = '''map(translate, atoms)'''
smt3 = '''[translate(i) for i in atoms]'''
time_for = timeit.Timer(setup=setup, stmt=smt1)
time_map = timeit.Timer(setup=setup, stmt=smt2)
time_lc = timeit.Timer(setup=setup, stmt=smt3)
print time_for.timeit(10000)
print time_map.timeit(10000)
print time_lc.timeit(10000)
随着说。 map
对我来说仍然较慢。
7.49916100502
7.83171486855
6.13082003593
并且列表理解胜出手。
然而,作为一种风格,我肯定会在这里使用for
循环。由于您没有从translate
返回任何内容,因此它是最干净的选择。使用map
和list-comprehensions
进行“副作用”通常不是首选做法。
答案 2 :(得分:2)
您的翻译功能错误,因为它实际返回None
。原子= [[1,1,1,1]]*1000
只不过是同一物体的副本1000次。
这是我的时间结果:
In [49]: def translate(x):
x[:3]=[y+1 for y in x[:3]]
return x
....:
In [54]: lis = [[1,1,1,1] for _ in xrange(10**5)]
使用map()
:
In [55]: %timeit map(translate,lis)
1 loops, best of 3: 151 ms per loop
有关环:
#this is fast as no list is created in this, i.e you're not storing the
#returned value anywhere. So technically it's not equivalent to a LC or `map`.
In [56]: %timeit for i in lis: translate(i)
1 loops, best of 3: 146 ms per loop
列表理解:
In [57]: %timeit [translate(i) for i in lis]
1 loops, best of 3: 153 ms per loop
来自docs:
Python支持几个循环结构。 for语句是 最常用的。它循环遍历序列的元素, 将每个分配给循环变量。如果你的循环体是 简单来说,for循环本身的解释器开销可以是一个 大量的开销。这是
map
函数的位置 很方便。您可以将地图视为移动到C代码中。唯一的 限制是map的“循环体”必须是函数调用。 除了列表推导的句法优势之外,它们通常比等效使用地图更快或更快。
因此,在大多数情况下map
仅在与built-in
函数一起使用时才优于列表推导。
答案 3 :(得分:0)
我无法在Python 3.3中复制您的结果(map
和range
现在都返回 lazy iterator 而不是列表):
In [7]: %timeit list(map(lambda x: x + 1, range(1000)))
1000 loops, best of 3: 218 us per loop
In [8]: %timeit [x + 1 for x in range(1000)]
10000 loops, best of 3: 99.5 us per loop
答案 4 :(得分:0)
请注意,您的两项操作会做不同的事情。
smt1
遍历您的列表,翻译每个项目并丢弃结果。 smt2
实际上翻译所有元素并返回包含所有已更改对象的列表。
因此,地图实际上比第一个语句更复杂,只是因为它存储了所有已翻译的项目。
您可以将第一个语句更改为列表推导,以使其返回相同的结果:
smt1 = '''[translate(i) for i in atoms]'''
当我这样做时,我得到以下结果:
3.8775811587063767 list comprehension
3.4751189085098315 map
另请注意,在Python 3中,map
成为了一个生成器。这意味着当您从中请求更多项目时, lazily 执行该翻译。所以这是在这里更喜欢地图的另一个原因。