为什么这段Python代码(将列表扩展与自身的映射合成)会使我的系统冻结?

为什么这段Python代码(将列表扩展与自身的映射合成)会使我的系统冻结?,python,lambda,freeze,Python,Lambda,Freeze,当我跑的时候 a = ['a'] a.extend(map(lambda x: 'b' + x, a)) 如果我在shell中以Python脚本的形式运行它,它会锁定我的系统,直到我可以执行Ctrl+C操作为止,而在解释器中运行它让我不得不硬关机 但是, a = ['a'] a.extend(list(map(lambda x: 'b' + x, a))) 工作正常,达到预期效果 为什么会发生这种情况 起初,我认为这可能是因为我试图用一个在a本身上运行的map函数来扩展a,所以我写道: a

当我跑的时候

a = ['a']
a.extend(map(lambda x: 'b' + x, a))
如果我在shell中以Python脚本的形式运行它,它会锁定我的系统,直到我可以执行Ctrl+C操作为止,而在解释器中运行它让我不得不硬关机

但是,

a = ['a']
a.extend(list(map(lambda x: 'b' + x, a)))
工作正常,达到预期效果

为什么会发生这种情况

起初,我认为这可能是因为我试图用一个在
a
本身上运行的map函数来扩展
a
,所以我写道:

a = ['a']
tmp = map(lambda x: 'b' + x, a)
a.extend(tmp)
然而,这也冻结了

类似地,这似乎效果不错:

a = ['a']
tmp = list(map(lambda x: 'b' + x, a))
a.extend(tmp)
为什么会这样


我在Python3.4.3上执行此操作,在Python3中,
map()
函数将生成一个迭代器

当看到
a.extend()
函数时,python会发现您希望使用与
a
相关的迭代器扩展列表
a
,并自动帮助您进行迭代

在这里,迭代开始了

首先,它是a中的一个
'a'
map()
函数中的迭代器给出
'a'
,从
lambda
表达式生成
'ba'
,并将其追加到列表
a
中<代码>一个现在变成了
['a','ba']

然后,
map()
函数中的迭代器发现,由于
a
的新pal
'ba'
的提交,对
a
进行迭代不会给出
StopIteration
。因此,
map()
函数中的迭代器为
lambda
提供了要处理的
'ba'
。一个
'bba'
在这里生成,并被推入
A

这就是
a
无限传播的工作原理

以下代码可能会有所帮助:

a = ['a']
import time
a.extend(map(lambda x: ('b' + x, print(x), time.sleep(1))[0], a))

理解为什么使用
list()
将迭代器转换为静态列表不会触发此操作应该很简单。

这是因为在Python 3.x中
map()
函数返回一个迭代器,该迭代器使用传递给它的列表的引用作为第二个参数。因此,当您在映射迭代器上迭代时,您也在扩展列表,这将无限期地继续下去,因此您要么得到
MemoryError
,要么最终得到一个无限循环

示例来显示此行为-

>>> m = map(lambda x: a.extend(x), a)
>>> m
<map object at 0x021E0E70>
>>> for i,x in enumerate(m):
...     print("Hello")
...
Hello
Hello
.... # lots of Hello
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
MemoryError
如果您尝试上面的代码,仍然会得到
MemoryError
或无限循环

当你这样做的时候-

a.extend(list(map(lambda x: 'b' + x, a)))
在扩展列表
a
之前,通过将迭代器转换为列表来使用迭代器,因此它不会以无限循环结束。在这种情况下,您正在执行类似的操作-

a = ['a']
templist = []
for x in a:
    templist.extend('b' + x)
a.extend(templist)

这就是为什么你没有得到这个错误。请注意,上面的代码可能不是python内部运行的方式,它只是一些类似的东西。

我认为python的对象管理机制不同于C/C++,请参见以下内容:

a = ['a'] 
a中x的
:
a、 附加('b')

如果您在Python命令行中键入,您将遇到一个无限循环,在输入CTRL+C之后

>>> a
您将得到一个包含'a'和'b'的长列表,我认为在for循环中,a.append('b')的a和a是相同的对象,在相同的内存中。
这就是我的想法。

这在Python2.7中很好用。*所以我猜问题在于,在Python3中,
map
函数返回一个
map对象(而不是Python2中的列表)。它在3.4.3和2.7.9Hum中都很好用。我的直觉和你最初的直觉是一样的——这是一个列表易变性问题。这两个版本在包装到list()中时都能工作(这是列表的一个副本),这是一个很好的线索。我的猜测是,没有列表代码的两个版本都在对原始列表进行变异(第二个版本通过指针进行变异),映射将继续扩展它们,从而导致无限循环。然而,列表易变性的后果以及Python对指针所做的奇怪事情远远超出了我的薪资等级,因此这可能是错误的……因此,当a列表正在更新并且a中x的
变得越来越长
a.append('b')
使得
a
越来越大,当下一个循环出现时,a:
中x的
a
与上一个循环不同,因为它附加了一个“b”。这是一个无限循环
>>> a