为什么这段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