Why does this code for initializing a list of lists apparently link the lists together?
The problem is that they're all the same exact list in memory. When you use the [x]*n
syntax, what you get is a list of n
many x
objects, but they're all references to the same object. They're not distinct instances, rather, just n
references to the same instance.
To make a list of 3 different lists, do this:
x = [[] for i in range(3)]
This gives you 3 separate instances of []
, which is what you want
[[]]*n
is similar to
l = []
x = []
for i in range(n):
x.append(l)
While [[] for i in range(3)]
is similar to:
x = []
for i in range(n):
x.append([]) # appending a new list!
In [20]: x = [[]] * 4
In [21]: [id(i) for i in x]
Out[21]: [164363948, 164363948, 164363948, 164363948] # same id()'s for each list,i.e same object
In [22]: x=[[] for i in range(4)]
In [23]: [id(i) for i in x]
Out[23]: [164382060, 164364140, 164363628, 164381292] #different id(), i.e unique objects this time
How to assign a value to nested list while keeping the original list in python
Use deepcopy instead, and don't initialise your lists with [[x]*n]*n
:
import copy
foo = [[0 for _ in range(3)] for _ in range(3)]
bar = copy.deepcopy(foo)
bar[0][0] = 1
print(foo)
print(bar)
Output:
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]
Creating a list of lists Python
grid = [[None]*20]*20 will give you a list of 20 sublists, each of which contains 20
None`s. However, all the sublists will be references to the same list in memory, so changing one will affect them all.
You're better off doing something like this:
grid = [[None for _ in xrange(20)] for __ in xrange(20)]
This will give you 20 distinct sublists, each of which contains 20 None
s
Further reading
a bug in nested lists assignment in Python
I know, it sounds wrong, but ...
This is not a bug, it's a feature.
>>> [id(x) for x in temp_list]
[4473545216, 4473545216, 4473545216]
As you can see, they all share the same reference. Therefore, you need to create a copy of the list.
Why does appending to one list also append to all other lists in my list of lists?
[[]]*2
is a list of two references to the same list. You are appending to it and then seeing it twice.
Python : List elements are connected, how to separate
Use eval
on repr
.
mylist = eval(repr([[0,0,0,0]]*3))
or use list comp to produce the list
mylist = [[0,0,0,0] for _ in range(3)]
List of lists changes reflected across sublists unexpectedly
When you write [x]*3
you get, essentially, the list [x, x, x]
. That is, a list with 3 references to the same x
. When you then modify this single x
it is visible via all three references to it:
x = [1] * 4
xs = [x] * 3
print(f"id(x): {id(x)}")
# id(x): 140560897920048
print(
f"id(xs[0]): {id(xs[0])}\n"
f"id(xs[1]): {id(xs[1])}\n"
f"id(xs[2]): {id(xs[2])}"
)
# id(xs[0]): 140560897920048
# id(xs[1]): 140560897920048
# id(xs[2]): 140560897920048
x[0] = 42
print(f"x: {x}")
# x: [42, 1, 1, 1]
print(f"xs: {xs}")
# xs: [[42, 1, 1, 1], [42, 1, 1, 1], [42, 1, 1, 1]]
To fix it, you need to make sure that you create a new list at each position. One way to do it is
[[1]*4 for _ in range(3)]
which will reevaluate [1]*4
each time instead of evaluating it once and making 3 references to 1 list.
You might wonder why *
can't make independent objects the way the list comprehension does. That's because the multiplication operator *
operates on objects, without seeing expressions. When you use *
to multiply [[1] * 4]
by 3, *
only sees the 1-element list [[1] * 4]
evaluates to, not the [[1] * 4
expression text. *
has no idea how to make copies of that element, no idea how to reevaluate [[1] * 4]
, and no idea you even want copies, and in general, there might not even be a way to copy the element.
The only option *
has is to make new references to the existing sublist instead of trying to make new sublists. Anything else would be inconsistent or require major redesigning of fundamental language design decisions.
In contrast, a list comprehension reevaluates the element expression on every iteration. [[1] * 4 for n in range(3)]
reevaluates [1] * 4
every time for the same reason [x**2 for x in range(3)]
reevaluates x**2
every time. Every evaluation of [1] * 4
generates a new list, so the list comprehension does what you wanted.
Incidentally, [1] * 4
also doesn't copy the elements of [1]
, but that doesn't matter, since integers are immutable. You can't do something like 1.value = 2
and turn a 1 into a 2.
Related Topics
Getting a Hidden Password Input
Creating a Range of Dates in Python
Handling Spreadsheet Data Through the Clipboard in Gtk
Check If One Package Is Installed in My System with Python
Python Library for Linux Process Management
Visibility of Global Variables in Imported Modules
Are Python Variables Pointers? or Else, What Are They
Why Is the Pygame Animation Is Flickering
What Is the Fastest Way to Send 100,000 Http Requests in Python
Read Specific Columns from a CSV File with CSV Module
Best Way to Replace Multiple Characters in a String
Import Error: No Module Name Urllib2
Dynamically Updating Plot in Matplotlib
What Is the Use of "Assert" in Python
How to Catch and Print the Full Exception Traceback Without Halting/Exiting the Program
How to Parse Dates with -0400 Timezone String in Python
How to Configure Chromedriver to Initiate Chrome Browser in Headless Mode Through Selenium