2010-09-06 15 views
151

widziałem istnieją właściwie dwa (a może więcej) sposoby łączenia list w Pythonie: Jednym ze sposobów jest użycie metody przedłużenia():Konkatenowanie dwie listy - różnicę między „+ =” i rozszerzenie()

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

drugi używać plus (+) operator:

b += a 

teraz zastanawiam: które z tych dwóch opcji jest „pythonic” sposób to zrobić listę konkatenacji i jest jakaś różnica między tymi dwoma (Sprawdziłem oficjalny samouczek w języku Python, ale nie znalazłem nic na ten temat).

+0

Może różnica ma więcej implikacje, jeśli chodzi o Duck Typing i jeśli * nie-być może-naprawdę-a-lista-ale-jak-a-lista * obsługuje '.__ iadd __()' /'.__add__() '/' .__ radd __() 'versus' .extend() ' –

+0

Obie pary idealnych pytań i odpowiedzi są głosowane równo! – Viney

Odpowiedz

150

Jedyną różnicą na poziomie kodu bajtowego jest to, że sposób .extend obejmuje wywołanie funkcji, które jest nieco droższe w Pythonie niż INPLACE_ADD.

To naprawdę nic, czym powinieneś się martwić, chyba że wykonujesz tę operację miliardy razy. Jest jednak prawdopodobne, że wąskie gardło leżałoby w innym miejscu.

+9

Może ta różnica ma więcej implikacji, jeśli chodzi o ducycjonowanie i jeśli Twoja * może nie tak naprawdę lista-ale-jak-lista * obsługuje '.__ iadd __()'/'.__ dodaj __()'/' .__ radd __() 'versus' .extend() ' –

+1

Ta odpowiedź nie wspomina o ważnych różnicach w scopingu. – wim

12

Według Zen of Python:

Simple is better than complex.

b += a jest bardziej proste niż b.extend(a).

Wbudowane elementy są tak wysoko zoptymalizowane, że nie występują rzeczywiste różnice w wydajności.

+7

"Powinien istnieć jeden - a najlepiej tylko jeden - czysty sposób na zrobienie tego". Czy to łamie regułę? – Zenadix

+1

@Zenadix Wydaje mi się, że są tylko te małe, śmieszne różnice, takie jak odpowiedź monitorów. – Trilarion

+3

To nie jest reguła. Chciałbym, żeby ludzie nie traktowali Zen Pythona tak poważnie - nie ma on implementacji. Odnośnie Zen jako wytycznych, a nie ścieżek technologicznych – holdenweb

107

Nie można użyć + = dla nielokalnego zmiennej (zmiennej, która nie jest lokalna dla funkcji, a także nie globalny)

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

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

    def boo(): 
     l += [5] 

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

main() 

To dlatego dla przedłużyć przypadku kompilator załaduje zmienną l korzystania LOAD_DEREF instrukcja, ale za to + = użyje LOAD_FAST - i masz *UnboundLocalError: local variable 'l' referenced before assignment*

+1

Mam trudności z twoim wyjaśnieniem "zmienna, która jest ** nie lokalna ** dla funkcji, a także ** nie globalna **" czy możesz podać przykład takiej zmiennej? –

+5

Zmienna "l" w moim przykładzie jest właśnie tego rodzaju. Nie jest lokalny dla funkcji "foo" i "boo" (poza ich zakresami), ale nie jest globalny (zdefiniowany wewnątrz "głównego" func, a nie na poziomie modułu). – monitorius

+1

Mogę potwierdzić, że ten błąd nadal występuje w pythonie 3.4.2 (aby wydrukować, musisz dodać nawiasy, ale wszystko inne może pozostać bez zmian). – trichoplax

13

można wywołania funkcji łańcuchowych, ale nie można + = wywołanie funkcji bezpośrednio:

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

Powiedziałbym, że jest jakaś różnica, jeśli chodzi o numpy (właśnie zobaczyłem, że pytanie pyta o połączenie dwóch list, a nie tablicy numpy, ale ponieważ może to być problem dla początkujących, takich jak ja, ja mam nadzieję, że może to pomóc komuś, kto szuka rozwiązania tego stanowiska), np.

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

powróci z błędem

ValueError: argumenty nie mogą być transmitowane wraz z kształtami (0,), (4,4,4)

b.extend(a) działa idealnie

2

Od pytona 3.5.2 kod źródłowy: Bez większych różnic.

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; 
} 
Powiązane problemy