2

I ran into a problem as described in this link. While using the dict comprehension I typed

keys = [x for x in range(21)]
value = [0,0]
dict1 = {key: value for key in keys}

instead of:

keys = [x for x in range(21)]
value = [0,0]
dict1 = {key: list(value) for key in keys}

In the former case, the problem remains. All the key values point to the same list. Why does this happen? In essence, what I don't understand is how does list([0,0]) not create a list as [[0,0]]?

EDIT: I understand that list(arg) takes only 1 argument. But what does it mean to run list over a list?

Community
  • 1
  • 1
ashishv
  • 181
  • 1
  • 3
  • 12
  • `list([0,0])` doesn't create `[[0,0]]` for the same reason that `list(0)` doesn't create `[0]`. That's just not what `list` does. – Kevin May 28 '15 at 19:19
  • I understand that, however why doesn't dict1 = {key: value for key in keys} work? – ashishv May 28 '15 at 19:21
  • `dict1 = {key: [0,0] for key in keys}` solve the problem in a more transparent way. – B. M. May 28 '15 at 20:17

5 Answers5

2

Let's say you have:

a = [0, 0]
b = list([0, 0])

Both a and b are lists containing the same values. But they're both unique instances of list.

Now, if you do:

c = a
d = b

c points to the same instance of a and d to b, so if you modify the values of c it'll be reflected in a as well (same goes with d and b).

However, if you do:

c = list(a)

You're basically creating a shallow copy of a. This means, you created a new list c containing the same values as those of a. So any mutation to c will not affect a since it's now a unique list instance.

Be careful though, if your list contains mutable objects they can still be mutated through the copied list. Use copy.deepcopy to ensure all objects are copied as new objects.

kratenko
  • 7,354
  • 4
  • 36
  • 61
sirfz
  • 4,097
  • 23
  • 37
1

Regarding your second question, "In essence, what I don't understand is how does list([0,0]) not create a list as [[0,0]]?"

The way the list() function works is that it takes as an argument some sort of container, specifically an iterable, and it iterates over this, putting each element in the container into a new list.

For example, a string is an iterable and each element is a single character:

>>> list('spam')
['s', 'p', 'a', 'm']

A tuple of integers is also iterable:

>>> list((1, 2, 3, 4))
[1, 2, 3, 4]

And of course, a list itself is iterable, so running list() on an existing list just makes a new list with the same contents:

>>> list(['oranges','spam',22.3])
['oranges', 'spam', 22.3]

What you can't do is pass an integer to list() as an integer is not iterable:

>>> list(42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
Eric Appelt
  • 2,843
  • 15
  • 20
0

You're creating a new list with list([0, 0]) versus using the same list over and over.

junnytony
  • 3,455
  • 1
  • 22
  • 24
0

list([0,0]) creates a new list object every time.

value = [0, 0]
v2 = list(value)
assert value == v2
assert id(value) != id(v2)
tzaman
  • 46,925
  • 11
  • 90
  • 115
0

list(x) means to make a new list from the contents of x, not to make a new one-element list containing x as its only element. The contents of your value are two numbers (both 0), so list(value) makes a new list containing two zeros.

In your first example, no new lists are ever created; the same list value is set as the value for every key.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384