Python 列表理解vs地图
是否有理由更喜欢使用Python 列表理解vs地图,python,list-comprehension,map-function,Python,List Comprehension,Map Function,是否有理由更喜欢使用map()而不是列表理解?它们中的一个通常比另一个更有效,还是被认为比另一个更具pythonic?map在某些情况下可能会在显微镜下更快(当您不是为此目的制作lambda,而是在map和listcomp中使用相同的函数时)。列表理解可能在其他情况下更快,大多数(并非全部)PythOnistas认为它们更直接和更清楚。 使用完全相同的功能时map的微小速度优势示例: $ python -mtimeit -s'xs=range(10)' 'map(hex, xs)' 100000
map()
而不是列表理解?它们中的一个通常比另一个更有效,还是被认为比另一个更具pythonic?map
在某些情况下可能会在显微镜下更快(当您不是为此目的制作lambda,而是在map和listcomp中使用相同的函数时)。列表理解可能在其他情况下更快,大多数(并非全部)PythOnistas认为它们更直接和更清楚。
使用完全相同的功能时map的微小速度优势示例:
$ 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
%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
%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
当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
map
在某些情况下可能会在显微镜下更快(如果您不是为此目的制作lambda,而是在map和listcomp中使用相同的函数)。列表理解可能在其他情况下更快,大多数(并非全部)PythOnistas认为它们更直接和更清楚。
使用完全相同的功能时map的微小速度优势示例:
$ 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
%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
%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
当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
我发现列表理解通常比映射更能表达我要做的事情-它们都能完成,但前者省去了试图理解复杂的lambda表达式的精神负担
还有一次采访(我一时找不到),Guido将
lambda
s和函数列为他最后悔接受Python的内容,因此,你可以提出这样的论点,即它们是非Pythonic的。我发现列表理解通常比映射更能表达我要做的事情-它们都能完成,但前者省去了试图理解复杂的lambda
表达式的精神负担
还有一次采访(我一时找不到),Guido将lambda和函数函数列为他最后悔接受Python的内容,因此你可以提出这样的论点,即它们是非Python的。这里有一个可能的例子:
map(lambda op1,op2: op1*op2, list1, list2)
与:
[op1*op2 for op1,op2 in zip(list1,list2)]
我猜如果坚持使用列表理解而不是地图,那么zip()是一种不幸的、不必要的开销。如果有人明确或否定地澄清这一点,那就太好了。这里有一个可能的情况:
map(lambda op1,op2: op1*op2, list1, list2)
与:
[op1*op2 for op1,op2 in zip(list1,list2)]
我猜如果坚持使用列表理解而不是地图,那么zip()是一种不幸的、不必要的开销。如果有人明确或否定地澄清这一点,那就太好了。案例
- 常见情况:几乎总是希望在python中使用列表理解,因为对于阅读代码的新手程序员来说,这样做更为明显。(这不适用于其他语言,因为其他习惯用法可能适用。)对于python程序员来说,这将更加明显,因为列表理解是python中迭代的事实标准;他们是被期待的
- 不太常见的情况:但是,如果您已经定义了一个函数,那么使用
通常是合理的,尽管它被认为是“非音速的”。例如,map
比map(sum,mylist)
更优雅/简洁。您获得了不必组成虚拟变量的优雅性(例如,[mylist中x的sum(x)]
或sum(x)代表x…
或sum(uuu)代表
),您只需键入两次即可进行迭代。对于sum(readableName)代表readableName…
和filter
以及reduce
模块中的任何内容,同样的论点也适用:如果您手头已经有一个函数,您可以继续进行一些函数编程。在某些情况下,这会增加可读性,而在其他情况下(例如,新手程序员、多个参数)则会失去可读性。。。但是代码的可读性在很大程度上取决于您的注释itertools
- 几乎从不使用
:在进行函数式编程时,您可能希望将map
函数作为纯抽象函数来使用,其中您正在映射map
,或者制作map
,或者将map
作为函数来讨论。例如,在Haskell中,一个名为map
的函子接口概括了任何数据结构上的映射。这在python中非常少见,因为python语法迫使您使用生成器样式来讨论迭代;你不能轻易概括它。(这有时是好的,有时是坏的。)您可能会想出一些罕见的python示例,其中fmap
是一件合理的事情。我能想到的最接近的例子是map(f,*list)
,这是一个简单的线性关系,大致相当于:sumEach=partial(map,sum)
- 只使用
-循环:当然也可以只使用for循环。从函数式编程的角度来看,虽然不是很优雅,但在命令式编程语言(如python)中,有时非局部变量会使代码更清晰,因为人们非常习惯以这种方式阅读代码。For循环通常也是最有效的,当您仅在执行任何不构建列表的复杂操作时(例如,求和或生成树等),列表理解和映射会得到优化,至少在内存方面是有效的(不一定是在时间方面,在最坏的情况下,我希望是一个常数,除非是一些罕见的病态垃圾收集打嗝)for
map
和
% 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>)
>>> 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
>>> 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
>>> 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
for x, y in somePoints:
# (several lines of code here)
squared = [x ** 2 for x in numbers]
# Oops, x was silently overwritten!
for x, y in somePoints:
# (several lines of code here)
squared = map(lambda x: x ** 2, numbers)
def square(x):
return x*x
squares = map(square, [1, 2, 3])
print(list(squares))
print(list(squares))
x_list = [(i, i+1, i+2, i*2, i-9) for i in range(1000)]
i_list = list(range(1000))
%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
%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
%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
In [1]: odd_cubes = [x ** 3 for x in range(10) if x % 2 == 1] # using a list comprehension
In [2]: odd_cubes_alt = list(map(lambda x: x ** 3, filter(lambda x: x % 2 == 1, range(10)))) # using map and filter
In [3]: odd_cubes == odd_cubes_alt
Out[3]: True
class DummyNum(object):
"""Dummy class"""
__slots__ = 'n',
def __init__(self, n):
self.n = n
def add(self):
self.n += 5
python -mtimeit -s "xs=range(123456)" "map(hex, xs)"
1000000 loops, best of 5: 218 nsec per loop
python -mtimeit -s "xs=range(123456)" "[hex(x) for x in xs]"
10 loops, best of 5: 19.4 msec per loop