list () и итеративная распаковка в Python 3.5+ - PullRequest
0 голосов
/ 27 сентября 2018

Есть ли практическая разница между list(iterable) и [*iterable] в версиях Python, которые поддерживают последний?

Ответы [ 4 ]

0 голосов
/ 27 сентября 2018

Всегда будут некоторые различия между двумя конструкциями, которые делают одно и то же.Дело в том, что я бы не сказал, что различия в этом случае на самом деле практичны .Оба являются выражениями, которые принимают итерируемое, итерируют по нему, а затем создают из него список.

Контракт такой же: вход - итеративный вывод, список, заполненный элементами итерируемого элемента.

Да, list может быть привязан к другому имени;list(it) - это вызов функции, а [*it] - отображение списка;[*it] быстрее с меньшими итерациями, но обычно выполняет то же самое с большими итерациями.Черт, можно даже добавить тот факт, что [*it] - это на три нажатия меньше.

Хотя это практично?Думаю ли я о них, когда пытаюсь получить список из итерируемого?Ну, может быть, нажатия клавиш для того, чтобы остаться под 79 символами и заставить линтера заткнуть его.

0 голосов
/ 27 сентября 2018

list(x) - это функция, [*x] - это выражение.Вы можете переназначить list и заставить его делать что-то еще (но вы не должны).

Говоря о cPython, b = list(a) переводит в эту последовательность байт-кодов:

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

Вместо этого c = [*a] становится:

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

, поэтому вы можете утверждать, что[*a] может быть немного более эффективным, но незначительно.

0 голосов
/ 27 сентября 2018

Поскольку [*iterable] распаковывается, он принимает синтаксис, подобный присвоению , в отличие от list(iterable):

>>> [*[]] = []
>>> list([]) = []
  File "<stdin>", line 1
SyntaxError: can't assign to function call

Подробнее об этом можно прочитать здесь (хотя это бесполезно).

Вы также можете использовать list(sequence=iterable), то есть с аргументом ключевого слова:

>>> list(sequence=[])
[]

Опять не полезно .

0 голосов
/ 27 сентября 2018

Вы можете использовать стандартный библиотечный модуль dis, чтобы исследовать байт-код, сгенерированный функцией.В этом случае:

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

Таким образом, есть разница, и это не только загрузка глобально определенного имени list, которая не должна происходить при распаковке.Таким образом, все сводится к тому, как определяется встроенная функция list и что именно делает BUILD_LIST_UNPACK.

Обратите внимание, что оба кода на самом деле намного меньше кода, чем написание стандартного списка для этого:

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