list() vs iterable unpacking in Python 3.5+

list(x) is a function, [*x] is an expression. You can reassign list, and make it do something else (but you shouldn't).

Talking about cPython, b = list(a) translates to this sequence of bytecodes:

LOAD_NAME                1 (list)
LOAD_NAME                0 (a)
CALL_FUNCTION            1
STORE_NAME               2 (b)

Instead, c = [*a] becomes:

LOAD_NAME                0 (a)
BUILD_LIST_UNPACK        1
STORE_NAME               3 (c)

so you can argue that [*a] might be slightly more efficient, but marginally so.


You can use the standard library module dis to investigate the byte code generated by a function. In this case:

import dis

def call_list(x):
    return list(x)

def unpacking(x):
    return [*x]

dis.dis(call_list)
#   2           0 LOAD_GLOBAL              0 (list)
#               2 LOAD_FAST                0 (x)
#               4 CALL_FUNCTION            1
#               6 RETURN_VALUE

dis.dis(unpacking)
#   2           0 LOAD_FAST                0 (x)
#               2 BUILD_LIST_UNPACK        1
#               4 RETURN_VALUE

So there is a difference and it is not only the loading of the globally defined name list, which does not need to happen with the unpacking. So it boils down to how the built-in list function is defined and what exactly BUILD_LIST_UNPACK does.

Note that both are actually a lot less code than writing a standard list comprehension for this:

def list_comp(x):
    return [a for a in x]

dis.dis(list_comp)
#   2           0 LOAD_CONST               1 (<code object <listcomp> at 0x7f65356198a0, file "<ipython-input-46-dd71fb182ec7>", line 2>)
#               2 LOAD_CONST               2 ('list_comp.<locals>.<listcomp>')
#               4 MAKE_FUNCTION            0
#               6 LOAD_FAST                0 (x)
#               8 GET_ITER
#              10 CALL_FUNCTION            1
#              12 RETURN_VALUE