Widziałem, że istnieją w rzeczywistości dwa (może więcej) sposoby łączenia list w Pythonie: Jednym ze sposobów jest użycie metody ext ():
a = [1, 2]
b = [2, 3]
b.extend(a)
drugi, aby użyć operatora plus (+):
b += a
Teraz zastanawiam się: która z tych dwóch opcji jest „pytonicznym” sposobem na łączenie list i czy istnieje między nimi różnica (przejrzałem oficjalny samouczek języka Python, ale nic nie mogłem znaleźć na ten temat).
.__iadd__()
/.__add__()
/ w.__radd__()
porównaniu.extend()
Odpowiedzi:
Jedyną różnicą na poziomie kodu bajtowego jest to, że
.extend
sposób obejmuje wywołanie funkcji, które jest nieco droższe w Pythonie niżINPLACE_ADD
.To naprawdę nie powinieneś się martwić, chyba że wykonasz tę operację miliardy razy. Jest jednak prawdopodobne, że wąskie gardło znalazłoby się w innym miejscu.
źródło
.__iadd__()
/.__add__()
/ w.__radd__()
porównaniu.extend()
Nie można użyć + = dla zmiennej nielokalnej (zmiennej, która nie jest lokalna dla funkcji, a także nie globalna)
Wynika to z tego, że dla rozszerzonego przypadku kompilator załaduje zmienną
l
za pomocąLOAD_DEREF
instrukcji, ale dla + = użyjeLOAD_FAST
- i otrzymasz*UnboundLocalError: local variable 'l' referenced before assignment*
źródło
Możesz łączyć wywołania funkcji, ale nie możesz + = wywołania funkcji bezpośrednio:
źródło
Powiedziałbym, że istnieje pewna różnica, jeśli chodzi o numpy (właśnie zobaczyłem, że pytanie dotyczy połączenia dwóch list, a nie tablicy numpy, ale ponieważ może to być problem dla początkujących, takich jak ja, mam nadzieję, że to może komuś pomóc którzy szukają rozwiązania tego postu), np.
wróci z błędem
ValueError: operandy nie można nadawać razem z kształtami (0,) (4,4,4)
b.extend(a)
działa świetnieźródło
Z kodu źródłowego CPython 3.5.2 : Brak dużej różnicy.
źródło
ext () działa z każdym iterowalnym *, + = działa z niektórymi, ale może stać się funky.
Python 3.6
* jest całkiem pewny, że .extend () działa z każdym iterowalnym, ale proszę o komentarz, jeśli się mylę
źródło
list.extend(iterable) Extend the list by appending all the items from the iterable. Equivalent to a[len(a):] = iterable.
Chyba odpowiedziałem na własną gwiazdkę.+=
operatora z obiektami różnego typu (w przeciwieństwie do dwóch list, jak w pytaniu), nie możesz oczekiwać, że uzyskasz konkatenację obiektów. I nie możesz oczekiwać, że zostanielist
zwrócony typ. Spójrz na swój kod, otrzymasznumpy.ndarray
zamiastlist
.Faktycznie, istnieją różnice pomiędzy tymi trzema opcjami:
ADD
,INPLACE_ADD
iextend
. Pierwsza jest zawsze wolniejsza, a pozostałe dwie są mniej więcej takie same.Korzystając z tych informacji, wolałbym użyć
extend
, który jest szybszy niżADD
i wydaje mi się bardziej wyraźny niż to, co robiszINPLACE_ADD
.Wypróbuj następujący kod kilka razy (dla Python 3):
źródło
ADD
zINPLACE_ADD
iextend()
.ADD
tworzy nową listę i kopiuje do niej elementy dwóch oryginalnych list. Na pewno będzie on wolniejszy niż działanie w miejscuINPLACE_ADD
iextend()
.Informacje te są zakopane w często zadawanych pytaniach dotyczących programowania :
Możesz to również zobaczyć w kodzie źródłowym CPython: https://github.com/python/cpython/blob/v3.8.2/Objects/listobject.c#L1000-L1011
źródło
Według Pythona do analizy danych.
„Należy zauważyć, że konkatenacja listy przez dodanie jest stosunkowo kosztowną operacją, ponieważ należy utworzyć nową listę i skopiować obiekty. Zazwyczaj preferowane jest użycie rozszerzania w celu dołączenia elementów do istniejącej listy, szczególnie w przypadku tworzenia dużej listy. „Tak więc
jest szybszy niż konkatenatywna alternatywa:
źródło
everything = everything + temp
niekoniecznie jest implementowany w taki sam sposób jakeverything += temp
.everything += temp
jest zaimplementowany w taki sposób, żeeverything
nie trzeba go kopiować. To właściwie czyni twoją odpowiedź sporną kwestią.