-1

Let's say I have an integer I want to make a list.

This works

[1]

However, this results in 'int' object is not iterable

list(1)

What is the difference between [] and list() and when is it appropriate to use each?

Luke
  • 50
  • 5
  • you gave `list()` an integer and not an iterable – stefan_aus_hannover Jan 12 '22 at 20:28
  • `[]` is part of a list literal ("list display", technically). `list` is a class, using `list(x)` is callling the list constructor with the argument `x`, where `x` must be an *iterable* – juanpa.arrivillaga Jan 12 '22 at 20:28
  • You've *seen* the difference. `list` takes an *iterable* as its argument and creates a list, one element per value from the iterable. `[...]` requires each value to be listed explicitly. They're not interchangeable, so it doesn't really make sense to ask when it is *appropriate* to use each; you use the one that actually fits your use case. – chepner Jan 12 '22 at 20:28
  • This is covered in the basic tutorial and python docs, so I am voting to close as requesting documentation. – Mad Physicist Jan 12 '22 at 20:28
  • 1
    @MadPhysicist It is actually not that easy to find this in the docs. – Jonathan Scholbach Jan 12 '22 at 20:31
  • Well, here's a functional duplicate: https://stackoverflow.com/q/23703109/2988730 – Mad Physicist Jan 12 '22 at 20:34

2 Answers2

2

They're entirely different things; list is a built-in and [] are operators that can be used for, for example, either list comprehension or for list initialisation (which is what you're doing), but also for accessing certain indices in containers, etc. So you're kind of comparing apples and oranges.

Between list with generator expressions and list comprehension, the latter is actually faster:

$ python3 -m timeit '[_ for _ in range(1000)]'
10000 loops, best of 5: 29.4 usec per loop
$ python3 -m timeit 'list(_ for _ in range(1000))'
5000 loops, best of 5: 42.9 usec per loop

If we disassemble into bytecode we get:

  • for list comprehension
>>> dis.dis('[_ for _ in range(10)]')
  1           0 LOAD_CONST               0 (<code object <listcomp> at 0x10d0647c0, file "<dis>", line 1>)
              2 LOAD_CONST               1 ('<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_NAME                0 (range)
              8 LOAD_CONST               2 (10)
             10 CALL_FUNCTION            1
             12 GET_ITER
             14 CALL_FUNCTION            1
             16 RETURN_VALUE

Disassembly of <code object <listcomp> at 0x10d0647c0, file "<dis>", line 1>:
  1           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                 8 (to 14)
              6 STORE_FAST               1 (_)
              8 LOAD_FAST                1 (_)
             10 LIST_APPEND              2
             12 JUMP_ABSOLUTE            4
        >>   14 RETURN_VALUE
  • for list plus a generator expression
>>> dis.dis('list(_ for _ in range(10))')
  1           0 LOAD_NAME                0 (list)
              2 LOAD_CONST               0 (<code object <genexpr> at 0x10d0647c0, file "<dis>", line 1>)
              4 LOAD_CONST               1 ('<genexpr>')
              6 MAKE_FUNCTION            0
              8 LOAD_NAME                1 (range)
             10 LOAD_CONST               2 (10)
             12 CALL_FUNCTION            1
             14 GET_ITER
             16 CALL_FUNCTION            1
             18 CALL_FUNCTION            1
             20 RETURN_VALUE

Disassembly of <code object <genexpr> at 0x10d0647c0, file "<dis>", line 1>:
  1           0 LOAD_FAST                0 (.0)
        >>    2 FOR_ITER                10 (to 14)
              4 STORE_FAST               1 (_)
              6 LOAD_FAST                1 (_)
              8 YIELD_VALUE
             10 POP_TOP
             12 JUMP_ABSOLUTE            2
        >>   14 LOAD_CONST               0 (None)
             16 RETURN_VALUE

So outside of having to look up the name (list, LOAD_NAME), it seems to be mostly down to internal design; that the generator expression is popping indicates a stack.


Compare this with what you were doing:

>>> dis.dis('[1]')
  1           0 LOAD_CONST               0 (1)
              2 BUILD_LIST               1
              4 RETURN_VALUE
>>> dis.dis('list(1)')
  1           0 LOAD_NAME                0 (list)
              2 LOAD_CONST               0 (1)
              4 CALL_FUNCTION            1
              6 RETURN_VALUE

First one builds a list, while the second is (after looking up the name) trying to call the function list (which actually is a mutable sequence type class).

ades
  • 227
  • 2
  • 14
0

list() takes an Iterable (for instance: instances of set, dict, tuple) as argument, [] takes an explicit listing of the elements or a comprehension.

Jonathan Scholbach
  • 4,925
  • 3
  • 23
  • 44