Объединение двух списков - разница между '+ =' и extend()
Я видел, что на самом деле есть два (возможно, более) способа объединения списков в Python:
Один из способов - использовать метод extend():
a = [1, 2]
b = [2, 3]
b.extend(a)
для использования оператора плюс (+):
b += a
Теперь я задаюсь вопросом: какой из этих двух вариантов является "путинским" способом выполнения конкатенации списков и есть ли разница между ними (я искал официальный учебник Python, но ничего не мог найти об этой теме).
Ответы
Ответ 1
Единственное отличие на уровне байт-кода заключается в том, что метод .extend
включает вызов функции, который немного дороже в Python, чем INPLACE_ADD
.
На самом деле вам ни о чем не стоит беспокоиться, если вы не выполняете эту операцию миллиарды раз. Вероятно, однако, что узкое место будет лежать в другом месте.
Ответ 2
Вы не можете использовать + = для нелокальной переменной (переменная, которая не является локальной для функции, а также не глобальной)
def main():
l = [1, 2, 3]
def foo():
l.extend([4])
def boo():
l += [5]
foo()
print l
boo() # this will fail
main()
Это потому, что для расширения case компилятор загрузит переменную l
с помощью команды LOAD_DEREF
, но для + = она будет использовать LOAD_FAST
- и вы получите *UnboundLocalError: local variable 'l' referenced before assignment*
Ответ 3
Вы можете связать вызовы функций, но вы не можете + = вызов функции напрямую:
class A:
def __init__(self):
self.listFoo = [1, 2]
self.listBar = [3, 4]
def get_list(self, which):
if which == "Foo":
return self.listFoo
return self.listBar
a = A()
other_list = [5, 6]
a.get_list("Foo").extend(other_list)
a.get_list("Foo") += other_list #SyntaxError: can't assign to function call
Ответ 4
В соответствии с Zen of Python:
Простой лучше, чем сложный.
b += a
проще, чем b.extend(a)
.
Встроенные функции настолько оптимизированы, что нет реальной разницы в производительности.
Ответ 5
Я бы сказал, что есть какая-то разница, когда он приходит с numpy (я только видел, что вопрос задает вопрос об объединении двух списков, а не в массиве numpy, но поскольку это может быть проблемой для новичков, таких как я, я надеюсь, что это может помочь кому-то, кто ищет решение этой должности), например.
import numpy as np
a = np.zeros((4,4,4))
b = []
b += a
он вернется с ошибкой
ValueError: операнды не могут быть переданы вместе с фигурами (0,) (4,4,4)
b.extend(a)
отлично работает
Ответ 6
Из исходного кода python 3.5.2:
Нет большой разницы.
static PyObject *
list_inplace_concat(PyListObject *self, PyObject *other)
{
PyObject *result;
result = listextend(self, other);
if (result == NULL)
return result;
Py_DECREF(result);
Py_INCREF(self);
return (PyObject *)self;
}
Ответ 7
extend() работает с любыми повторяемыми *, + = работает с некоторыми, но может стать фанк.
import numpy as np
l = [2, 3, 4]
t = (5, 6, 7)
l += t
l
[2, 3, 4, 5, 6, 7]
l = [2, 3, 4]
t = np.array((5, 6, 7))
l += t
l
array([ 7, 9, 11])
l = [2, 3, 4]
t = np.array((5, 6, 7))
l.extend(t)
l
[2, 3, 4, 5, 6, 7]
Python 3.6
* уверен, что .extend() работает с любой итерацией, но, пожалуйста, прокомментируйте, если я ошибаюсь
Ответ 8
Согласно Python для анализа данных.
"Обратите внимание, что конкатенация списков путем добавления является сравнительно дорогой операцией, поскольку необходимо создать новый список и скопировать объекты. Использование предпочтительного расширения для добавления элементов в существующий список, особенно если вы создаете большой список, обычно предпочтительнее". Таким образом,
everything = []
for chunk in list_of_lists:
everything.extend(chunk)
быстрее конкатенативной альтернативы:
everything = []
for chunk in list_of_lists:
everything = everything + chunk
![enter image description here]()
Ответ 9
На самом деле, существует различие между тремя вариантами: ADD
, INPLACE_ADD
и extend
. Первый всегда медленнее, а два других примерно одинаковы.
Имея эту информацию, я бы предпочел использовать extend
, которое работает быстрее ADD
и кажется мне более явным из того, что вы делаете, чем INPLACE_ADD
.
Попробуйте следующий код несколько раз (для Python 3):
import time
def test():
x = list(range(10000000))
y = list(range(10000000))
z = list(range(10000000))
# INPLACE_ADD
t0 = time.process_time()
z += x
t_inplace_add = time.process_time() - t0
# ADD
t0 = time.process_time()
w = x + y
t_add = time.process_time() - t0
# Extend
t0 = time.process_time()
x.extend(y)
t_extend = time.process_time() - t0
print('ADD {} s'.format(t_add))
print('INPLACE_ADD {} s'.format(t_inplace_add))
print('extend {} s'.format(t_extend))
print()
for i in range(10):
test()
ADD 0.3540440000000018 s
INPLACE_ADD 0.10896000000000328 s
extend 0.08370399999999734 s
ADD 0.2024550000000005 s
INPLACE_ADD 0.0972940000000051 s
extend 0.09610200000000191 s
ADD 0.1680199999999985 s
INPLACE_ADD 0.08162199999999586 s
extend 0.0815160000000077 s
ADD 0.16708400000000267 s
INPLACE_ADD 0.0797719999999913 s
extend 0.0801490000000058 s
ADD 0.1681250000000034 s
INPLACE_ADD 0.08324399999999343 s
extend 0.08062700000000689 s
ADD 0.1707760000000036 s
INPLACE_ADD 0.08071900000000198 s
extend 0.09226200000000517 s
ADD 0.1668420000000026 s
INPLACE_ADD 0.08047300000001201 s
extend 0.0848089999999928 s
ADD 0.16659500000000094 s
INPLACE_ADD 0.08019399999999166 s
extend 0.07981599999999389 s
ADD 0.1710910000000041 s
INPLACE_ADD 0.0783479999999912 s
extend 0.07987599999999873 s
ADD 0.16435900000000458 s
INPLACE_ADD 0.08131200000001115 s
extend 0.0818660000000051 s