0

After a little time banging my head against the wall, my example can be simply expressed as shown:

lists = [list()] * 5
print(f"Number of empty lists = {len([l for l in lists if len(l) == 0])}")
lists[0].append(0)
print(f"Number of empty lists = {len([l for l in lists if len(l) == 0])}")

lists = [list() for _ in range(5)]
print(f"Number of empty lists = {len([l for l in lists if len(l) == 0])}")
lists[0].append(0)
print(f"Number of empty lists = {len([l for l in lists if len(l) == 0])}")

This provides the following output:

Number of empty lists = 5
Number of empty lists = 0
Number of empty lists = 5
Number of empty lists = 4

The difference is the way in which the variable lists is initialised. It seems that the first way is in fact just a lot of references to the same variable, whilst the latter is an actual list of independent variables. My question is why? What possible advantages could the first method provide? Why aren't these the same thing?

  • If I change one variable, say by appending to a list, they all change. There is a large chance for confusion and I cannot see why would these two methods not provide me with a list of copies.

  • If I wanted a list of the same thing over and over again, then why do I need a list at all - it seems like the code requires restructuring.

  • If I wanted to share properties of things but only sometimes, we have class attributes for that.

Thank you for any info in advance!

Matt
  • 43
  • 4
  • https://stackoverflow.com/questions/240178/list-of-lists-changes-reflected-across-sublists-unexpectedly – Thierry Lathuille Jul 25 '22 at 12:00
  • Rule of thumb: don't use list multiplication, ever. Use `[list() for _ in range(5)]` instead. – chepner Jul 25 '22 at 12:04
  • (Or at the very least, treat list multiplication as a shortcut to use in interactive shells for when you *know* it is safe, rather than the canonical way to create such lists.) – chepner Jul 25 '22 at 12:05
  • Let's say we use `random.randrange(10)` instead of `list()` to fill the list. First method would give us, for example `[4]`, which you then mulitply few times to get `[4, 4, 4, 4, 4]` - there is no way to get different numbers because initial list contains just `4`. With 2nd method, you make a **separate call to `randrange`** each time, so you would get potentially different number each time for something like this : `[8, 2, 7, 0, 2, 3]`. – matszwecja Jul 25 '22 at 12:17
  • But why do you even have a list at this point? Surely a cleaner solution is to just assign your result such as `my_value = random.randrange(10)`, and if there is a need to iterate over something, then we can use `my_value` whenever we like. It's also more memory efficient (not that it matters for a list of 10 things, but with scale, this may be important). – Matt Aug 10 '22 at 09:13

0 Answers0