Why is this Python code (linking a list extension with a map of itself) causing my system to freeze?

When i started

a = ['a'] a.extend(map(lambda x: 'b' + x, a)) 

it locks my system until I can do Ctrl + C if I run it as a Python script from the shell, and running it from the interpreter made me hard disconnect my laptop.

However

 a = ['a'] a.extend(list(map(lambda x: 'b' + x, a))) 

It works fine and gives the expected result.

Why is this happening?

At first, I thought it could be because I was trying to extend a with a display function that ran on a , so I wrote:

 a = ['a'] tmp = map(lambda x: 'b' + x, a) a.extend(tmp) 

However, it also froze.

Similarly, this works fine:

 a = ['a'] tmp = list(map(lambda x: 'b' + x, a)) a.extend(tmp) 

Why is this happening?

I am doing this in Python 3.4.3 .

+5
source share
3 answers

This is because an iterator is returned in the Python 3.x map() function, which uses the list link passed to it as the second parameter. Since you are repeating a map iterator, you are also expanding the list, and it goes on forever, so you either get a MemoryError or end with an infinite loop.

An example to show this behavior is

 >>> 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 

So, when you do - a.extend(map(lambda x: 'b' + x, a)) . You do something similar -

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

If you try the code above, you still get a MemoryError or an infinite loop.

When you do that -

 a.extend(list(map(lambda x: 'b' + x, a))) 

You use an iterator, converting it to a list, before expanding the list of a , therefore, it does not end with an infinite loop. In this case, you are doing something similar to -

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

That is why you are not getting an error. Please note that the above code may not be the same as python internally runs map , its just something similar.

+3
source

In python 3, an iterator will be created from the map() function.

When viewing the a.extend() function, python will find that you want to expand the list of a with the iterator associated with a and automatically help you to iterate through it.

And here the iteration begins.

First, a 'a' in a. The iterator inside the map() function gives 'a' , a 'ba' is created from your lambda expression and added to list a . a now becomes ['a', 'ba'] .

Then the iterator inside the map() function detects that iterating over a does not give StopIteration due to a new buddy 'ba' . So the iterator inside the map() function provides 'ba' for lambda to handle. Here A 'bba' generated and inserted into a .

How a infinite spread works.

The following code may help:

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

And it should be trivial to understand why using list() to convert an iterator to a static list does not cause this.

+2
source

I think the Python object management mechanism is different from C / C ++, see this:

 a = ['a'] 

for x in a: a.append('b')

if you type your Python command line, you will come across an infinite loop and after entering CTRL + C and

 >>> a 

you will get a long list containing "a" and "b", and I think for a while loop a and a.append ("b") are the same object and in the same memory. This is what I think.

+1
source

All Articles