列表理解与地图

Tim*_*man 680 python list-comprehension map-function

是否有理由更喜欢使用map()超过列表理解,反之亦然?它们中的任何一个通常比另一个更有效或被认为是更加pythonic?

Ale*_*lli 625

map在某些情况下(当你没有为此目的制作lambda,但在map和listcomp中使用相同的函数时)可能在显微镜下更快.在其他情况下,列表推导可能更快,并且大多数(并非所有)pythonistas认为它们更直接和更清晰.

使用完全相同的功能时,地图的微小速度优势的一个例子:

$ python -mtimeit -s'xs=range(10)' 'map(hex, xs)'
100000 loops, best of 3: 4.86 usec per loop
$ python -mtimeit -s'xs=range(10)' '[hex(x) for x in xs]'
100000 loops, best of 3: 5.58 usec per loop
Run Code Online (Sandbox Code Playgroud)

当map需要lambda时,如何完全颠倒性能比较的示例:

$ python -mtimeit -s'xs=range(10)' 'map(lambda x: x+2, xs)'
100000 loops, best of 3: 4.24 usec per loop
$ python -mtimeit -s'xs=range(10)' '[x+2 for x in xs]'
100000 loops, best of 3: 2.32 usec per loop
Run Code Online (Sandbox Code Playgroud)

  • `map(operator.attrgetter('foo'),objs)`比`[oj在objs中为foo更容易]`? (56认同)
  • @Alex:我不想在这里引入不必要的名字,比如`o`,你的例子说明了原因. (51认同)
  • 不要在Alex的无限样式点上进行kibash,但有时候地图似乎更容易读给我:data = map(str,some_list_of_objects).其他一些...... operator.attrgetter,operator.itemgetter等. (44认同)
  • 是的,确实我们的内部Python风格指南在工作中明确地推荐listcomps对照地图和过滤器(甚至没有提到微小但可衡量的性能改进地图在某些情况下可以提供;-). (37认同)
  • 我认为@GreggLind有一个观点,他的`str()`例子. (28认同)
  • FWIW,我相信他的意思是"[o.foo for o in objs]",而不是"[o.foo for foo in objs]" (26认同)
  • 亚历克斯,你不像我一样懒惰......因为这个原因,我通常会"从运营商导入项目作为iget,attrgetter作为aget"! (5认同)
  • @AlexMartelli但是......`map(operator.attrgetter('foo'),objs)`和`[oj在objs中为foo]`不做同样的事.-.什么来自`o`?如果你的意思是"[foo.foo for foo in objs]",我更加怀疑哪一个实际上更容易阅读(是的,我知道,4年后) (5认同)
  • 在当前版本中,情况非常不同.在我的机器上(Windows 8.1,Python 3.4,参考C实现),列表推导的所有配置或`list(map(...))`与`lambda`或显式定义的函数的速度大致相同,尽管有明确的` list`调用现在需要的.同时,内置函数或方法的等效使用速度超过两倍.(我的测试使用`def test(x):return x + 1`,`lambda x:x + 1`或`(1).__ add__`作为应用于`range(100)`的函数.) (5认同)
  • 在 Python 3 中,“map”版本将生成一个迭代器,这意味着它将使用比列表理解更少的内存。这使得它比列表理解快得多。使用生成器理解更接近,但仍然更慢。 (3认同)
  • 任何语言的最佳编码实践之一是重用现有代码,并且**特别是避免手动编码标准算法可以完成工作的循环/理解**。算法的名称说明了意图,其实现正是这样做的,而循环需要额外的时间和精力来解析实现并在头脑中理解意图,无论实现多么简单。标准算法的实现可能会表现得更好,并且在 2021 年 11 月 29 日,在 Ubuntu 20.04 LTS 中,**Python 3.8 `map` 在第一个 `timeit` 示例上快了 7 倍,在第二个示例上快了 3.5 倍**。 (3认同)
  • 我不同意更直接和更清晰的说法,对我来说 `map(int, stuff)` 比 `[int(x) for x in stuff]` 更清晰,不需要随机变量。这取决于您是否有功能经验。映射的存在时间也比列表推导式要长得多。每个都有它的用途,并且两者都应该是您工具带中的工具。此外,地图是惰性的,因此您可以将其传递直到需要它为止,而合成将在其写入的行上完成。 (2认同)

nin*_*cko 441

案例

  • 常见情况:几乎总是如此,你会想在python中使用列表推导,因为你对新手程序员阅读代码所做的更为明显.(这不适用于其他语言可能适用的其他语言.)你对python程序员所做的更为明显,因为列表推导是Python中迭代的事实上的标准; 他们是预期的.
  • 不太常见的情况:但是如果你已经定义了一个函数,它通常是合理的map,虽然它被认为是'unpythonic'.例如,比map(sum, myLists)它更优雅/简洁[sum(x) for x in myLists].你获得不必弥补虚拟变量(如的风采sum(x) for x...sum(_) for _...sum(readableName) for readableName...),你必须输入两次,只是进行迭代.同样的道理也适用于filterreduce从什么itertools模块:如果你已经有一个方便的功能,你可以继续前进,做一些函数式编程.这在某些情况下会增加可读性,在其他情况下会丢失(例如,新手程序员,多个参数)......但是代码的可读性在很大程度上取决于您的评论.
  • 几乎从来没有:您可能需要使用该map功能作为一个纯抽象功能而做功能编程,在那里你映射map,或讨好map,或以其他方式谈论受益map的功能.例如,在Haskell中,一个函数接口称为fmap泛化任何数据结构的映射.这在python中非常罕见,因为python语法迫使你使用生成器风格来讨论迭代; 你不能轻易地概括它.(这有时很好,有时也很糟糕.)你可能会想出一些罕见的python例子,这map(f, *lists)是合理的事情.我能想出的最接近的例子是sumEach = partial(map,sum),这是一个非常大致相当于以下内容的单线程:

def sumEach(myLists):
    return [sum(_) for _ in myLists]
Run Code Online (Sandbox Code Playgroud)
  • 只需使用for-loop:您当然也可以使用for循环.虽然从功能编程的角度来看并不那么优雅,但有时​​非局部变量会使命令式编程语言(如python)中的代码更加清晰,因为人们习惯于以这种方式阅读代码.当你只是进行任何复杂的操作时,for循环通常也是最有效的,这些操作没有构建像list-comprehensions这样的列表,并且map被优化(例如求和,或者做树等) - 至少在记忆方面有效(不一定是在时间方面,我认为在最坏的情况下是一个恒定的因素,除非一些罕见的病态垃圾收集打嗝).

"Pythonism"

我不喜欢"pythonic"这个词,因为我没有发现pythonic在我眼中总是很优雅.尽管如此,mapfilter类似的功能(如非常有用的itertools模块)在风格方面可能被认为是非语音的.

怠惰

就效率而言,就像大多数函数式编程结构一样,MAP可能是LaZY,而事实上它在python中是懒惰的.这意味着您可以执行此操作(在python3中),并且您的计算机不会耗尽内存并丢失所有未保存的数据:

>>> map(str, range(10**100))
<map object at 0x2201d50>
Run Code Online (Sandbox Code Playgroud)

尝试使用列表理解:

>>> [str(n) for n in range(10**100)]
# DO NOT TRY THIS AT HOME OR YOU WILL BE SAD #
Run Code Online (Sandbox Code Playgroud)

请注意,列表推导也本质上是懒惰的,但是python选择将它们实现为非惰性.尽管如此,python确实以生成器表达式的形式支持惰性列表推导,如下所示:

>>> (str(n) for n in range(10**100))
<generator object <genexpr> at 0xacbdef>
Run Code Online (Sandbox Code Playgroud)

您基本上可以将[...]语法视为将生成器表达式传递给列表构造函数,例如list(x for x in range(5)).

简短的人为例子

from operator import neg
print({x:x**2 for x in map(neg,range(5))})

print({x:x**2 for x in [-y for y in range(5)]})

print({x:x**2 for x in (-y for y in range(5))})
Run Code Online (Sandbox Code Playgroud)

列表推导是非惰性的,因此可能需要更多内存(除非您使用生成器理解).方括号[...]通常会使事情变得明显,尤其是在括号中.另一方面,有时你最终会像打字一样啰嗦[x for x in....只要保持迭代器变量很短,如果不缩进代码,列表推导通常会更清晰.但是你总是可以缩进你的代码.

print(
    {x:x**2 for x in (-y for y in range(5))}
)
Run Code Online (Sandbox Code Playgroud)

或打破局面:

rangeNeg5 = (-y for y in range(5))
print(
    {x:x**2 for x in rangeNeg5}
)
Run Code Online (Sandbox Code Playgroud)

python3的效率比较

map 现在很懒:

% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=map(f,xs)'
1000000 loops, best of 3: 0.336 usec per loop            ^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

因此,如果您不使用所有数据,或者不提前知道您需要多少数据,那么mappython3(以及python2或python3中的生成器表达式)将避免在必要的最后时刻之前计算它们的值.通常这通常会超过使用的任何开销map.缺点是python与大多数函数式语言相比非常有限:如果从"按顺序"从左到右访问数据,则只能获得此优势,因为python生成器表达式只能按顺序进行评估x[0], x[1], x[2], ....

但是,假设我们有一个f我们想要的预制函数map,我们忽略了map立即强制评估的懒惰list(...).我们得到一些非常有趣的结果:

% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(map(f,xs))'                                                                                                                                                
10000 loops, best of 3: 165/124/135 usec per loop        ^^^^^^^^^^^^^^^
                    for list(<map object>)

% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=[f(x) for x in xs]'                                                                                                                                      
10000 loops, best of 3: 181/118/123 usec per loop        ^^^^^^^^^^^^^^^^^^
                    for list(<generator>), probably optimized

% python3 -mtimeit -s 'xs=range(1000)' 'f=lambda x:x' 'z=list(f(x) for x in xs)'                                                                                                                                    
1000 loops, best of 3: 215/150/150 usec per loop         ^^^^^^^^^^^^^^^^^^^^^^
                    for list(<generator>)
Run Code Online (Sandbox Code Playgroud)

结果是AAA/BBB/CCC形式,其中A是在大约2010年英特尔工作站上使用python 3执行的.?.?,B和C是使用带有python 3.2.1的大约2013 AMD工作站执行的,硬件极其不同.结果似乎是地图和列表推导在性能方面具有可比性,受其他随机因素的影响最大.我们可以告诉的唯一的事情似乎是,奇怪的是,虽然我们期待列表解析[...]比生成表情表现得更好(...),map也更高效,发电机表达式(再次假设计算所有的值/使用).

重要的是要意识到这些测试假设一个非常简单的功能(身份功能); 但这很好,因为如果功能很复杂,那么与程序中的其他因素相比,性能开销可以忽略不计.(用其他简单的东西测试可能仍然很有趣f=lambda x:x+x)

如果你擅长阅读python程序集,你可以使用该dis模块来查看幕后是否真的发生了什么:

>>> listComp = compile('[f(x) for x in xs]', 'listComp', 'eval')
>>> dis.dis(listComp)
  1           0 LOAD_CONST               0 (<code object <listcomp> at 0x2511a48, file "listComp", line 1>) 
              3 MAKE_FUNCTION            0 
              6 LOAD_NAME                0 (xs) 
              9 GET_ITER             
             10 CALL_FUNCTION            1 
             13 RETURN_VALUE         
>>> listComp.co_consts
(<code object <listcomp> at 0x2511a48, file "listComp", line 1>,)
>>> dis.dis(listComp.co_consts[0])
  1           0 BUILD_LIST               0 
              3 LOAD_FAST                0 (.0) 
        >>    6 FOR_ITER                18 (to 27) 
              9 STORE_FAST               1 (x) 
             12 LOAD_GLOBAL              0 (f) 
             15 LOAD_FAST                1 (x) 
             18 CALL_FUNCTION            1 
             21 LIST_APPEND              2 
             24 JUMP_ABSOLUTE            6 
        >>   27 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

 

>>> listComp2 = compile('list(f(x) for x in xs)', 'listComp2', 'eval')
>>> dis.dis(listComp2)
  1           0 LOAD_NAME                0 (list) 
              3 LOAD_CONST               0 (<code object <genexpr> at 0x255bc68, file "listComp2", line 1>) 
              6 MAKE_FUNCTION            0 
              9 LOAD_NAME                1 (xs) 
             12 GET_ITER             
             13 CALL_FUNCTION            1 
             16 CALL_FUNCTION            1 
             19 RETURN_VALUE         
>>> listComp2.co_consts
(<code object <genexpr> at 0x255bc68, file "listComp2", line 1>,)
>>> dis.dis(listComp2.co_consts[0])
  1           0 LOAD_FAST                0 (.0) 
        >>    3 FOR_ITER                17 (to 23) 
              6 STORE_FAST               1 (x) 
              9 LOAD_GLOBAL              0 (f) 
             12 LOAD_FAST                1 (x) 
             15 CALL_FUNCTION            1 
             18 YIELD_VALUE          
             19 POP_TOP              
             20 JUMP_ABSOLUTE            3 
        >>   23 LOAD_CONST               0 (None) 
             26 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

 

>>> evalledMap = compile('list(map(f,xs))', 'evalledMap', 'eval')
>>> dis.dis(evalledMap)
  1           0 LOAD_NAME                0 (list) 
              3 LOAD_NAME                1 (map) 
              6 LOAD_NAME                2 (f) 
              9 LOAD_NAME                3 (xs) 
             12 CALL_FUNCTION            2 
             15 CALL_FUNCTION            1 
             18 RETURN_VALUE 
Run Code Online (Sandbox Code Playgroud)

似乎使用[...]语法比使用语法更好list(...).可悲的是,这个map类对于反汇编来说有点不透明,但我们可以通过速度测试来实现.

  • "非常有用的itertools模块[在]风格方面可能被认为是非语音的".嗯.我也不喜欢"Pythonic"这个词,所以在某种意义上我并不关心它意味着什么,但我不认为那些使用它的人是公平的,说根据"Pythonicness"内置的` map`和`filter`以及标准库`itertools`本质上是坏的风格.除非GvR实际上说它们要么是一个可怕的错误,要么仅仅是为了表现,如果这就是"Pythonicness"所说的那个唯一的自然结论是忘记它是愚蠢的;-) (5认同)
  • @SteveJessop:实际上,[Guido认为丢弃`map` /`filter`对于Python 3来说是个好主意](http://www.artima.com/weblogs/viewpost.jsp?thread=98196),只有叛逆其他Pythonistas将它们保存在内置命名空间中(而`reduce`被移动到`functools`).我个人不同意(`map`和`filter`很好用预定义的,特别是内置的函数,如果需要'lambda`,就永远不要使用它们),但GvR基本上称它们不是Pythonic多年. (4认同)
  • @SteveJessop:我只是在处理`map` /`filter`,而不是`itertools`.函数式编程完全是Pythonic(`itertools`,`functools`和`operator`都是专门针对函数式编程设计的,我一直在Python中使用函数习语),而`itertools`提供的功能很痛苦实现自己,特别是`map`和`filter`是生成器表达式的冗余,这使得Guido讨厌它们.`itertools`一直很好. (2认同)
  • 如果有办法的话,我可以喜欢这个答案。解释得很好。 (2认同)

Meh*_*dad 90

您应该使用mapfilter不是列表推导.

即使它们不是"Pythonic",你应该更喜欢它们的客观原因是:
它们需要函数/ lambdas作为参数,这引入了一个新的范围.

我不止一次被这个咬过了:

for x, y in somePoints:
    # (several lines of code here)
    squared = [x ** 2 for x in numbers]
    # Oops, x was silently overwritten!
Run Code Online (Sandbox Code Playgroud)

但如果相反我说:

for x, y in somePoints:
    # (several lines of code here)
    squared = map(lambda x: x ** 2, numbers)
Run Code Online (Sandbox Code Playgroud)

那么一切都会好起来的.

你可以说我在同一范围内使用相同的变量名称是愚蠢的.

我不是.代码原本很好 - 两个x不在同一范围内.
只是在我内部块移动到代码的不同部分后才出现问题(读取:维护期间出现问题,而不是开发),我没想到.

是的,如果你从未犯过这个错误,那么列表理解就更优雅了.
但是从个人经验(以及看到其他人犯同样的错误)我已经看到它发生了足够多次,我认为当这些错误蔓延到你的代码中时,你不得不经历这种痛苦.

结论:

使用mapfilter.它们可以防止难以诊断的与范围相关的细微错误.

边注:

不要忘记考虑使用imapifilter(in itertools)它们是否适合您的情况!

  • 这个错误在Python 3中[修复](http://stackoverflow.com/a/4199355/596361) (83认同)
  • 对不起,但是你在2012年末写了这篇文章,好在python 3出现之后,答案就像你推荐一种不受欢迎的python编码风格,因为你在切割时被一个bug咬了粘贴代码.我从未声称自己很聪明或经验丰富,我只是不同意你的理由证明了大胆的主张是正当的. (12认同)
  • @wim:这只是关于Python 2,但如果你想保持向后兼容,它适用于Python 3.我知道它并且我已经使用Python一段时间了(是的,不仅仅是几个月),但它发生在我身上.我见过比我聪明的其他人陷入了同样的陷阱.如果你是如此聪明和/或经验丰富,这对你来说不是问题,那么我很高兴你,我不认为大多数人都喜欢你.如果是这样的话,就不会有这样的冲动在Python 3中修复它. (11认同)
  • @wim:嗯?Python 2仍然在很多地方使用,Python 3存在的事实并没有改变这一点.当你说"对于使用Python超过几个月的任何人而言,这并不是一个微妙的错误"时,这句话的字面意思是"这只涉及没有经验的开发人员"(显然不是你).而且为了记录,你显然没有看到答案,因为我用*粗体*说我**移动**,而不是复制,代码.复制粘贴错误在各种语言中非常统一.由于它的范围,这种bug对于Python来说更加独特; 它更微妙,更容易忘记和错过. (7认同)
  • 感谢您指出了这一点.我没有明确地想到列表理解是在同一范围内并且可能是一个问题.话虽如此,我认为其他一些答案清楚地表明列表理解应该是大部分时间的默认方法,但这是需要记住的.这也是一个很好的一般提醒,保持函数(因此范围)小,并具有彻底的单元测试和使用断言语句. (5认同)
  • 切换到"map"和/或"filter"仍然不是一个合乎逻辑的理由.如果有的话,避免你的问题的最直接和逻辑的翻译不是`map(lambda x:x**2,数字)`而是一个生成器表达式`list(x**2代表x的数字)`正如JeromeJ已经指出的那样,没有泄漏.看看Mehrdad,不要亲自动手,我只是强烈不同意你的推理. (3认同)
  • @wim:嗯,我的意思是,如果你不同意,那么你不同意,除了反对你的观点之外,我无能为力.关于生成器,它仍然没有更好,因为列表必须经历大量的重新分配(而地图知道列表将是多久的先验).坦率地说,如果你使用的是生成器,那么你应该使用`imap`,而不是`map`,这完全改变了问题.但是如果你只是想找到一个理由来选择答案那么就保持你的downvote ...我没有太多其他的说实话. (2认同)

rae*_*aek 41

实际上,map列表推导在Python 3语言中的表现完全不同.看看下面的Python 3程序:

def square(x):
    return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))
Run Code Online (Sandbox Code Playgroud)

您可能希望它两次打印"[1,4,9]"行,而是打印"[1,4,9]"后跟"[]".你第一次看squares它似乎表现为三个元素的序列,但第二次作为空元素.

在Python 2语言中map返回一个简单的旧列表,就像列表推导在两种语言中一样.关键是mapPython 3(以及imapPython 2)中的返回值不是列表 - 它是一个迭代器!

迭代迭代器时会消耗元素,这与迭代列表时不同.这就是为什么squares在最后print(list(squares))一行看起来为空的原因.

总结一下:

  • 在处理迭代器时,你必须记住它们是有状态的,并且当你遍历它们时它们会发生变异.
  • 列表更具可预测性,因为它们仅在您明确改变它们时才会更改; 它们是容器.
  • 还有一个好处:数字,字符串和元组更加可预测,因为它们根本无法改变; 他们是价值观.


Dan*_*Dan 16

我发现列表理解通常更能表达我想要做的事情map- 它们都完成了它,但前者节省了试图理解什么是复杂lambda表达的心理负担.

在那里也有一个采访(我无法随意找到)Guido列出lambdas和功能函数作为他最接近Python接受的事情,所以你可以通过美德来证明他们是非Pythonic那个.

  • 是的,叹了口气,但是Guido最初在Python 3中完全删除lambda的意图得到了一次游说反对它,所以尽管我支持得很好,他还是回过头去了 - 好吧,猜测lambda在很多*SIMPLE*案例中太方便了,当它超过*SIMPLE*边界或被分配给一个名称(!在后一种情况下,它是高清的愚蠢步履蹒跚重复 - )唯一的问题是. (9认同)
  • 你正在考虑的采访是这样的:http://www.amk.ca/python/writing/gvr-interview,Guido 在那里说 *“有时我接受贡献的速度太快了,后来意识到这是一个错误。一个例子是一些函数式编程特性,例如 lambda 函数。lambda 是一个关键字,可让您创建一个小的匿名函数;诸如 map、filter 和 reduce 等内置函数在序列上运行函数类型,例如列表。”* (3认同)
  • @Alex,我没有你多年的经验,但我看到了比lambdas更复杂的列表理解.当然,滥用语言特征总是难以抗拒的诱惑.有趣的是,列表理解(经验上)似乎比lambdas更容易被滥用,尽管我不确定为什么会出现这种情况.我还要指出,"蹒跚"并不总是坏事.减少"这条线可能正在做的事情"的范围有时可以使读者更容易.例如,C++中的`const`关键字是沿着这些方向取得的巨大成功. (3认同)

Mik*_*rns 16

如果您计划编写任何异步,并行或分布式代码,您可能更喜欢map列表解析 - 因为大多数异步,并行或分布式包提供了一个map函数来重载python map.然后通过将适当的map函数传递给代码的其余部分,您可能不必修改原始的串行代码以使其并行运行(等).


And*_*ndz 15

这是一个可能的情况:

map(lambda op1,op2: op1*op2, list1, list2)
Run Code Online (Sandbox Code Playgroud)

与:

[op1*op2 for op1,op2 in zip(list1,list2)]
Run Code Online (Sandbox Code Playgroud)

我猜你的zip()是一个不幸和不必要的开销,如果你坚持使用列表推导而不是地图,你需要沉迷.如果有人澄清这一点是肯定的还是消极的,那将是很好的.

  • 我想我还是更喜欢`map(operator.mul,list1,list2)`.正是在这些非常简单的左侧表达式上,理解变得笨拙. (5认同)
  • 添加一个非常晚的评论,你可以使用`itertools.izip`使`zip`懒惰 (4认同)
  • 应该是"for"而不是"from"在你的第二个代码引用,@ andz和@ weakish的评论中.我以为我发现了一种新的语法方法来列出理解...... Darn. (2认同)

vis*_*ell 7

所以,由于Python 3 map()是一个迭代器,你需要记住你需要什么:迭代器或list对象.

正如@AlexMartelli已经提到的,map()只有在你不使用lambda函数时才比列表理解更快.

我会告诉你一些时间比较.

Python 3.5.2和CPython
我使用了Jupiter笔记本,特别是%timeit内置的魔术命令
测量:s == 1000 ms == 1000*1000μs= 1000*1000*1000 ns

建立:

x_list = [(i, i+1, i+2, i*2, i-9) for i in range(1000)]
i_list = list(range(1000))
Run Code Online (Sandbox Code Playgroud)

内置功能:

%timeit map(sum, x_list)  # creating iterator object
# Output: The slowest run took 9.91 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 277 ns per loop

%timeit list(map(sum, x_list))  # creating list with map
# Output: 1000 loops, best of 3: 214 µs per loop

%timeit [sum(x) for x in x_list]  # creating list with list comprehension
# Output: 1000 loops, best of 3: 290 µs per loop
Run Code Online (Sandbox Code Playgroud)

lambda 功能:

%timeit map(lambda i: i+1, i_list)
# Output: The slowest run took 8.64 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 325 ns per loop

%timeit list(map(lambda i: i+1, i_list))
# Output: 1000 loops, best of 3: 183 µs per loop

%timeit [i+1 for i in i_list]
# Output: 10000 loops, best of 3: 84.2 µs per loop
Run Code Online (Sandbox Code Playgroud)

还有生成器表达这样的东西,参见PEP-0289.所以我认为将它添加到比较中会很有用

%timeit (sum(i) for i in x_list)
# Output: The slowest run took 6.66 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 495 ns per loop

%timeit list((sum(x) for x in x_list))
# Output: 1000 loops, best of 3: 319 µs per loop

%timeit (i+1 for i in i_list)
# Output: The slowest run took 6.83 times longer than the fastest. 
# This could mean that an intermediate result is being cached.
# 1000000 loops, best of 3: 506 ns per loop

%timeit list((i+1 for i in i_list))
# Output: 10000 loops, best of 3: 125 µs per loop
Run Code Online (Sandbox Code Playgroud)

你需要list对象:

如果是自定义函数,请使用list comprehension,list(map())如果有内置函数则使用

你不需要list对象,你只需要可迭代的对象:

一直用map()!