2010-09-06 2 views
151

Я видел есть на самом деле два (возможно больше) способов конкатенации списков в Python: Одним из способов является использование метода расширения():Конкатенация два списка - разница между «+ =» и расширения()

a = [1, 2] 
b = [2, 3] 
b.extend(a) 

другой, чтобы использовать плюс (+) оператор:

b += a 

Теперь я задаюсь вопросом: Какой из этих двух вариантов является «вещий» способ сделать список конкатенации и есть разница между этими двумя (Я просмотрел официальный учебник Python, но ничего не мог найти в этой теме).

+0

Может быть, разница имеет больше значения, когда речь идет о утиной типизации и если ваш * возможно, не-очень-а-список, но, как-а-лист * поддерживает '.__ iadd __()' /'.__add__() '/' .__ radd __() 'versus' .extend() ' –

+0

Идеальная Q & A пара проголосовали одинаково! – Viney

ответ

150

Единственная разница на уровне байт-кода заключается в том, что способ .extend включает вызов функции, который немного дороже в Python, чем INPLACE_ADD.

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

+9

Возможно, разница имеет большее значение, когда дело доходит до ducktyping, и если ваш * возможно-не-действительно-список-но-как-список * поддерживает '.__ iadd __()'/'.__ add __()'/' .__ radd __() 'versus' .extend() ' –

+1

В этом ответе не упоминаются важные различия в области видимости. – wim

12

Согласно Zen of Python:

Simple is better than complex.

b += a является более простым, чем b.extend(a).

Встроенные функции настолько оптимизированы, что нет реальной разницы в производительности.

+7

«Должен быть один - и желательно только один - простой способ сделать это». Разве это нарушает правило? – Zenadix

+1

@ Zenadix Я думаю, что он делает только эти смешные небольшие различия, такие как ответ мониторов. – Trilarion

+3

Это не правило. Я бы хотел, чтобы люди не воспринимали Дзэн Питона так серьезно - у него нет реализации. Обращайтесь к Дзен как к руководящим принципам, а не к трамвайным линиям – holdenweb

107

Вы не можете использовать + = для нелокальной переменной (переменной, которая не является локальным для функции, а также не глобальный)

def main(): 
    l = [1, 2, 3] 

    def foo(): 
     l.extend([4]) 

    def boo(): 
     l += [5] 

    foo() 
    print l 
    boo() # this will fail 

main() 

Это потому, что для продлить случай компилятор будет загружать переменную l с помощью LOAD_DEREF инструкция, но + = он будет использовать LOAD_FAST - и вы получите *UnboundLocalError: local variable 'l' referenced before assignment*

+1

У меня возникают трудности с вашим объяснением «переменная, которая ** не является локальной ** для функции, а также ** не глобальной **». Можете ли вы привести пример такой переменной? –

+5

Переменная 'l' в моем примере точно такая. Он не является локальным для функций «foo» и «boo» (вне их областей), но он не является глобальным (определяется внутри «main» func, а не на уровне модуля). – monitorius

+1

Я могу подтвердить, что эта ошибка все еще встречается с python 3.4.2 (вам нужно будет добавить круглые скобки для печати, но все остальное останется неизменным). – trichoplax

13

вы можете вызовы функций цепи, но вы не можете + = функция вызова непосредственно:

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

Я бы сказал, что есть какая-то разница, когда он приходит с numpy (я просто видел, что вопрос задает вопрос о объединении двух списков, а не в массиве numpy, но поскольку это может быть проблемой для новичка, например, я, я надеюсь, это может помочь кому-то, кто ищет решение этой должности), например.

import numpy as np 
a = np.zeros((4,4,4)) 
b = [] 
b += a 

он вернется с ошибкой

ValueError: операнды не могут передаваться вместе с формами (0,) (4,4,4)

b.extend(a) прекрасно работает

2

От питона 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; 
} 
Смежные вопросы