Ponieważ string
nie można zmienić Pythona , zastanawiałem się, jak połączyć łańcuch bardziej efektywnie?
Mogę tak napisać:
s += stringfromelsewhere
lub tak:
s = []
s.append(somestring)
later
s = ''.join(s)
Pisząc to pytanie, znalazłem dobry artykuł mówiący na ten temat.
http://www.skymind.com/~ocrow/python_string/
Ale jest w Pythonie 2.x., więc pytanie brzmiałoby: czy coś się zmieniło w Pythonie 3?
Odpowiedzi:
Najlepszym sposobem dołączania ciąg do zmiennej łańcuchowej jest użycie
+
lub+=
. Jest tak, ponieważ jest czytelny i szybki. Są również tak szybkie, który wybierzesz jest kwestią gustu, ten drugi jest najczęstszy. Oto czasy ztimeit
modułem:Jednak ci, którzy zalecają posiadanie list i dołączanie do nich, a następnie dołączanie do nich, robią to, ponieważ przypuszczenie dodania łańcucha do listy jest prawdopodobnie bardzo szybkie w porównaniu z przedłużeniem łańcucha. W niektórych przypadkach może to być prawda. Tutaj, na przykład, milion dołącza jednoznakowy ciąg, najpierw do ciągu, a następnie do listy:
OK, okazuje się, że nawet jeśli wynikowy ciąg ma milion znaków, dołączanie było jeszcze szybsze.
Teraz spróbujmy dodać łańcuch o długości tysiąca znaków sto tysięcy razy:
Końcowy ciąg ma zatem długość około 100 MB. To było dość powolne, dołączanie do listy było znacznie szybsze. Że ten czas nie obejmuje finału
a.join()
. Jak długo to zajmie?Ups. Okazuje się, że nawet w tym przypadku dołączanie / łączenie przebiega wolniej.
Skąd więc ta rekomendacja? Python 2?
Cóż, dołączanie / łączenie jest tam marginalnie szybsze, jeśli używasz bardzo długich ciągów (którymi zwykle nie jesteś, jaki miałbyś ciąg, który ma 100 MB pamięci?)
Ale prawdziwym klinicerem jest Python 2.3. Gdzie nawet nie pokażę ci czasu, ponieważ jest tak wolny, że jeszcze się nie skończył. Te testy nagle trwają minuty . Z wyjątkiem append / join, który jest tak samo szybki jak w późniejszych Pythonach.
Tak. Łączenie strun było bardzo powolne w Pythonie w epoce kamienia łupanego. Ale w wersji 2.4 już go nie ma (a przynajmniej Python 2.4.7), więc zalecenie użycia append / join stało się nieaktualne w 2008 roku, kiedy Python 2.3 przestał być aktualizowany i powinieneś przestać go używać. :-)
(Aktualizacja: Okazuje się, gdy przeprowadziłem testowanie ostrożniej niż przy użyciu
+
i+=
jest szybsze dla dwóch łańcuchów w Pythonie 2.3. Zalecenia dotyczące używania''.join()
muszą być nieporozumieniem)Jest to jednak CPython. Inne wdrożenia mogą mieć inne obawy. I to tylko kolejny powód, dla którego przedwczesna optymalizacja jest źródłem wszelkiego zła. Nie używaj techniki, która powinna być „szybsza”, chyba że najpierw ją zmierzysz.
Dlatego „najlepszą” wersją do łączenia łańcuchów jest użycie + lub + = . A jeśli okaże się to dla ciebie powolne, co jest dość mało prawdopodobne, zrób coś innego.
Dlaczego więc używam dużo append / join w moim kodzie? Ponieważ czasami jest to wyraźniejsze. Zwłaszcza gdy wszystko, co powinieneś połączyć, powinno być oddzielone spacjami, przecinkami lub znakami nowej linii.
źródło
Jeśli łączysz wiele wartości, to żadna z nich. Dołączanie listy jest drogie. Możesz do tego użyć StringIO. Zwłaszcza jeśli budujesz go przez wiele operacji.
Jeśli masz już pełną listę z innej operacji, po prostu użyj
''.join(aList)
Z python FAQ: Jaki jest najbardziej efektywny sposób łączenia wielu ciągów razem?
Edycja: Byłem głupiutki i wyniki wkleiłem wstecz, dzięki czemu wyglądało na to, że dołączanie do listy było szybsze niż cStringIO. Dodałem również testy dla bytearray / str concat, a także drugą rundę testów przy użyciu większej listy z większymi ciągami. (python 2.7.3)
Przykład testu ipython dla dużych list ciągów
źródło
cStringIO
nie istnieje w Py3. Użyjio.StringIO
zamiast tego.W Pythonie> = 3.6 nowy ciąg f jest skutecznym sposobem na konkatenację łańcucha.
źródło
Zalecaną metodą jest nadal dołączanie i dołączanie.
źródło
Jeśli łączone łańcuchy są literałami, użyj Łańcuchowego łączenia literałów
Jest to przydatne, jeśli chcesz skomentować część ciągu (jak wyżej) lub jeśli chcesz użyć nieprzetworzonych ciągów lub potrójnych cudzysłowów dla części literału, ale nie dla wszystkich.
Ponieważ dzieje się tak na warstwie składni, używa zerowych operatorów konkatenacji.
źródło
Piszesz tę funkcję
Następnie możesz dzwonić, gdziekolwiek chcesz
źródło
str_join = lambda *str_list: ''.join(s for s in str_list)
Używanie w miejscu konkatenacji ciągu przez „+” jest NAJGORSZĄ metodą konkatenacji pod względem stabilności i implementacji krzyżowej, ponieważ nie obsługuje wszystkich wartości. Standard PEP8 odradza to i zachęca do używania format (), join () i append () do długotrwałego użytkowania.
Zgodnie z cytowaną sekcją „Zalecenia dotyczące programowania”:
źródło
Choć nieco przestarzały, Kod Like a Pythonista: Idiomatic Python zaleca
join()
się+
w tej sekcji . Podobnie jak PythonSpeedPerformanceTips w swojej sekcji dotyczącej łączenia łańcuchów , z następującym zastrzeżeniem:źródło
Jak wspomina @jdi, dokumentacja Pythona sugeruje użycie
str.join
lubio.StringIO
do łączenia łańcuchów. I mówi, że programista powinien oczekiwać kwadratowego czasu+=
w pętli, mimo że istnieje optymalizacja od Python 2.4. Jak mówi ta odpowiedź:Pokażę przykład kodu z prawdziwego świata, który naiwnie polegał na
+=
tej optymalizacji, ale nie miał zastosowania. Poniższy kod konwertuje iterowalne krótkie ciągi znaków na większe fragmenty, które mają być używane w zbiorczym interfejsie API.Ten kod może działać literacko przez wiele godzin z powodu kwadratowej złożoności czasu. Poniżej znajdują się alternatywy z sugerowanymi strukturami danych:
I mikro-benchmark:
źródło
Możesz to zrobić na różne sposoby.
To małe podsumowanie stworzyłem, zamieszczając następujące artykuły.
źródło
mój przypadek użycia był nieco inny. Musiałem skonstruować zapytanie, w którym ponad 20 pól było dynamicznych. Zastosowałem to podejście przy użyciu metody formatowania
było to dla mnie stosunkowo prostsze zamiast używania + lub innych sposobów
źródło
Możesz także użyć tego (bardziej wydajnego). ( /software/304445/why-is-s-better-than-for-concatenation )
źródło