Какой идиоматический синтаксис для добавления в короткий список Python? - PullRequest
455 голосов
/ 16 декабря 2011

list.append() - очевидный выбор для добавления в конец списка. Вот разумное объяснение для пропавших без вести list.prepend(). Если предположить, что мой список короткий и проблемы с производительностью незначительны, это

list.insert(0, x)

или

list[0:0] = [x]

идиоматических

Ответы [ 5 ]

661 голосов
/ 16 декабря 2011

Форма s.insert(0, x) является наиболее распространенной.

Всякий раз, когда вы видите это, возможно, пришло время подумать об использовании collection.deque вместо списка.

221 голосов
/ 05 июня 2012

Если вы можете пойти по функциональному пути, следующее довольно ясно

new_list = [x] + your_list

Конечно, вы не вставили x в your_list, скорее, вы создали новый список с x приготовился к этому.

70 голосов
/ 05 июня 2015

Каков идиоматический синтаксис для добавления в короткий список Python?

Обычно вы не хотите повторяться перед списком в Python.

Если это короткий , и вы не делаете это много ... тогда хорошо.

list.insert

list.insert можно использовать таким образом.

list.insert(0, x)

Но это неэффективно, потому что в Python list - это массив указателей, и теперь Python должен взять каждый указатель в списке и переместить его вниз на один, чтобы вставить указатель на ваш объект в первом слоте, так что это действительно эффективно только для довольно коротких списков, как вы спрашиваете.

Если вам нужен контейнер, эффективный для добавления элементов, вам нужен список с двумя связями. У Python есть один - он называется deque.

deque.appendleft

A collections.deque имеет много методов списка. list.sort является исключением, делая deque окончательно не полностью заменяющим Лискова вместо list.

>>> set(dir(list)) - set(dir(deque))
{'sort'}

deque также имеет метод appendleft (равно как popleft). deque - это двусторонняя очередь и двусвязный список - независимо от длины, всегда требуется одинаковое количество времени для предварительной подготовки чего-либо. В больших обозначениях O время O (1) и время O (n) для списков. Вот использование:

>>> import collections
>>> d = collections.deque('1234')
>>> d
deque(['1', '2', '3', '4'])
>>> d.appendleft('0')
>>> d
deque(['0', '1', '2', '3', '4'])

deque.extendleft

Также актуальным является метод extendleft в deque, который итеративно добавляет:

>>> from collections import deque
>>> d2 = deque('def')
>>> d2.extendleft('cba')
>>> d2
deque(['a', 'b', 'c', 'd', 'e', 'f'])

Обратите внимание, что каждый элемент будет добавляться по одному за раз, что эффективно меняет их порядок.

Производительность list против deque

Сначала мы настроим итеративное добавление:

import timeit
from collections import deque

def list_insert_0():
    l = []
    for i in range(20):
        l.insert(0, i)

def list_slice_insert():
    l = []
    for i in range(20):
        l[:0] = [i]      # semantically same as list.insert(0, i)

def list_add():
    l = []
    for i in range(20):
        l = [i] + l      # caveat: new list each time

def deque_appendleft():
    d = deque()
    for i in range(20):
        d.appendleft(i)  # semantically same as list.insert(0, i)

def deque_extendleft():
    d = deque()
    d.extendleft(range(20)) # semantically same as deque_appendleft above

и производительность:

>>> min(timeit.repeat(list_insert_0))
2.8267281929729506
>>> min(timeit.repeat(list_slice_insert))
2.5210217320127413
>>> min(timeit.repeat(list_add))
2.0641671380144544
>>> min(timeit.repeat(deque_appendleft))
1.5863927800091915
>>> min(timeit.repeat(deque_extendleft))
0.5352169770048931

Deque намного быстрее. Поскольку списки становятся длиннее, я ожидаю, что deque будет работать еще лучше. Если вы можете использовать deque's extendleft, вы, вероятно, получите лучшую производительность таким образом.

56 голосов
/ 03 марта 2015

Если кто-то найдет такой вопрос, как я, вот мои тесты производительности предложенных методов:

Python 2.7.8

In [1]: %timeit ([1]*1000000).insert(0, 0)
100 loops, best of 3: 4.62 ms per loop

In [2]: %timeit ([1]*1000000)[0:0] = [0]
100 loops, best of 3: 4.55 ms per loop

In [3]: %timeit [0] + [1]*1000000
100 loops, best of 3: 8.04 ms per loop

Как видите, insert и назначение слайса почти в два раза быстрее, чем явное добавлениеочень близки в результатах.Как отметил Раймонд Хеттингер , insert является более распространенным вариантом, и я лично предпочитаю этот способ добавления к списку.

4 голосов
/ 16 декабря 2011

Первый, безусловно, намного понятнее и выражает намерение гораздо лучше: вы хотите вставить только один элемент, а не целый список.

...