c+=map(lambda n:n*2,c)杀死python3 shell。为什么?

2024-09-28 19:26:01 发布

您现在位置:Python中文网/ 问答频道 /正文

Python 3.6.4 (v3.6.4:d48ecebad5, Dec 18 2017, 21:07:28)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> c = [1, 2]
>>> c += map(lambda n: n *2, range(1, 3))
>>> c
[1, 2, 2, 4]
>>> c = [1, 2]
>>> c += map(lambda n: n *2, c)
Killed!

但是,python2也是如此,它的map结果是一个列表,这与python3中的生成器不同。那为什么c += map(lambda n: n *2, range(1, 3))会起作用呢?你知道吗


Tags: lambdabuildmapappleontypehelprange
1条回答
网友
1楼 · 发布于 2024-09-28 19:26:01

c += fooc = c.__iadd__(foo)等价。如果c是一个列表,list.__iadd__方法接受任何iterable,包括一个生成器表达式:

>>> x = []
>>> x += (i for i in range(3))
>>> x
[0, 1, 2]

即使list.__add__不支持生成器表达式:

>>> x + (i for i in range(3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "generator") to list

python3中的代码崩溃是因为map生成器在被扩展的相同的列表上迭代,但是当前位置总是尾部后面的两个元素。从迭代器中提取新元素时,list.__iadd__始终会将新元素逐个添加到末尾;此时,map生成器持有的列表迭代器使用的索引将递增。。。但是在列表的末尾添加了一个新元素,所以在当前迭代位置之后总是有2个元素,最终Python会耗尽内存或者计算机会因为交换而停止运行。你知道吗

也就是说,这种行为与

for elem in c:
    c.append(elem * 2)

(以Wim为荣)

Python2版本的工作原理正是因为map将在调用c.__iadd__之前创建一个列表;一个包含2个元素的新列表将传递给c.__iadd__。同样地,c += map(lambda n: n * 2, range(1, 3))也可以工作,因为在python2中,range(1, 3)将创建一个新列表,而在python3中,它将创建一个range sequence对象,两者都是不同的

如果将map替换为生成器表达式,也可以触发Python 2中的病理行为:

Python 2.7.15rc1 (default, Nov 12 2018, 14:31:15) 
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> x = [1, 2]
>>> x += (n * 2 for n in x)

相关问题 更多 >