2

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?

6
  • you gave list() an integer and not an iterable Commented Jan 12, 2022 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 Commented Jan 12, 2022 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. Commented Jan 12, 2022 at 20:28
  • This is covered in the basic tutorial and python docs, so I am voting to close as requesting documentation. Commented Jan 12, 2022 at 20:28
  • 1
    @MadPhysicist It is actually not that easy to find this in the docs. Commented Jan 12, 2022 at 20:31

2 Answers 2

3

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).

Sign up to request clarification or add additional context in comments.

2 Comments

[] isn't really an operator
I meant that [ and ] each are operators, but maybe I'm using the wrong term
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.