6

I was trying to create a list with n empty lists inside of it, but faced an interesting situation.

Firstly I tried the following:

>>> n = 3
>>> list([]) * n
[]

It creates an empty list.

After that I tried the following line, which creates an empty list, too:

>>> list(list()) * n
[]

But when I try the same with literals,

>>> [[]] * n 
[[], [], []]

it gives the correct output. Can someone explain why?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Sekomer
  • 688
  • 1
  • 6
  • 24
  • 1
    Have you seen what `list(list())` compared to `[[]]`? Why do you *expect* these to work the same? Using the list constructor never works like a list literal – juanpa.arrivillaga Apr 04 '21 at 22:03
  • Note that `[[]] * n` likely *doesn't* give the correct output, as you'll find if you try to append to any of the inner lists - https://stackoverflow.com/q/240178/3001761. `list([])` is the same as `list(list())`, because `list()` gives you an empty list `[]`. – jonrsharpe Apr 04 '21 at 22:03
  • As an aside, you almost certainly don't want to use `columns = [[]] * n` because this creates a list with `n` references *to the same empty list* – juanpa.arrivillaga Apr 04 '21 at 22:04
  • 1
    `[[]]` is not equal to `list(list())` – Ahmad Anis Apr 04 '21 at 22:04
  • list() creates a list if no parameters are passed to it. If an iterable is passed to it, it returns a list with iterables items as values (think converting string or tuple). You can see then, if list() creates an empty list, a list([]) will return a list, containing values of an empty list, i.e. an empty list. – dm2 Apr 04 '21 at 22:06

1 Answers1

13

list(...) is not interchangeable with [...]. You can wrap square brackets around things to get nested lists, but wrapping things in list() doesn't have the same effect.

  • When you write [[]] you get a list with a single element. That element is [].

  • When you write list([]) the list constructor takes an iterable and creates a list with the same elements. If you wrote list(['foo', 'bar']) the result would be ['foo', 'bar']. Writing list([]) yields [].

    This form is more useful when you pass iterables that aren't lists. Other examples:

    list('abc') == ['a', 'b', 'c']         # strings are iterables over their characters
    list(('foo', 'bar')) == ['foo', 'bar'] # tuple
    list({'foo', 'bar'}) == ['foo', 'bar'] # set; could get ['bar', 'foo'] instead
    
  • list(list()) is equivalent to list([]). And we've seen that's in turn equivalent to [].

Stay away from [[]] * n when creating a multidimensional list. It will create a list with n references to the same list object and will bite you when you try to modify the internal lists. It's a common mistake that everyone makes. Use this instead, which will create a separate empty list for each slot:

[[] for i in range(n)]

Further reading:

John Kugelman
  • 349,597
  • 67
  • 533
  • 578