Czy istnieje wydajna metoda konkatenacji ciągów masy w Pythonie (jak StringBuilder w C # lub StringBuffer w Javie)? Znalazłem tutaj następujące metody :
- Proste łączenie przy użyciu
+
- Korzystanie z listy ciągów i
join
metody - Korzystanie
UserString
zMutableString
modułu - Korzystanie z tablicy znaków i
array
modułu - Korzystanie
cStringIO
zStringIO
modułu
Ale czego używają lub sugerują eksperci i dlaczego?
f''
ciągi formatujące, które będą szybsze niż jakiekolwiek alternatywy w poprzednich wersjach Pythona.Odpowiedzi:
Może Cię to zainteresować: Anegdota optymalizacyjna Guido. Chociaż warto również pamiętać, że jest to stary artykuł i poprzedza istnienie takich rzeczy jak
''.join
(chociażstring.joinfields
wydaje mi się, że jest mniej więcej to samo)W związku z tym
array
moduł może być najszybszy, jeśli uda się włożyć w niego problem. Ale''.join
prawdopodobnie jest wystarczająco szybki i ma tę zaletę, że jest idiomatyczny, a przez to łatwiejszy do zrozumienia dla innych programistów Pythona.Wreszcie złota zasada optymalizacji: nie optymalizuj, chyba że wiesz, że musisz, i mierz zamiast zgadywać.
Za pomocą
timeit
modułu możesz mierzyć różne metody . Które mogą powiedzieć ci, który jest najszybszy, zamiast przypadkowych nieznajomych na domysły przygotowywania www.źródło
.join()
? Głównym pytaniem jest, czy a) utworzyć kopię ciągu do konkatenacji (podobnie jaks = s + 'abc'
), co wymaga O (n) runtime, czy b) po prostu dołączyć do istniejącego ciągu bez tworzenia kopii, co wymaga O (1) ?''.join(sequenceofstrings)
jest to, co zwykle działa najlepiej - najprostsze i najszybsze.źródło
''.join(sequence)
idiom. Jest to szczególnie przydatne do tworzenia list oddzielonych przecinkami:', '.join([1, 2, 3])
podaje ciąg'1, 2, 3'
."".join(chr(x) for x in xrange(65,91))
--- w tym przypadku argumentem do złączenia jest iterator utworzony za pomocą wyrażenia generatora. Nie ma tymczasowej listy, która została utworzona.Python 3.6 zmienił grę pod kątem konkatenacji ciągów znanych komponentów za pomocą dosłownej interpolacji ciągów .
Biorąc pod uwagę przypadek testowy z odpowiedzi mkoistinena , mając ciągi
Pretendenci są
f'http://{domain}/{lang}/{path}'
- 0,151 µs'http://%s/%s/%s' % (domain, lang, path)
- 0,321 µs'http://' + domain + '/' + lang + '/' + path
- 0,356 µs''.join(('http://', domain, '/', lang, '/', path))
- 0,249 µs (zauważ, że budowanie krotki o stałej długości jest nieco szybsze niż tworzenie listy o stałej długości).Zatem obecnie najkrótszy i najpiękniejszy możliwy kod jest również najszybszy.
W wersjach alfa Pythona 3.6 implementacja
f''
łańcuchów była najwolniejsza z możliwych - w rzeczywistości wygenerowany kod bajtowy jest prawie równoważny z''.join()
przypadkiem niepotrzebnych wywołań, dostr.__format__
których bez argumentów po prostu zwracałbyself
niezmieniony. Te nieefektywności zostały usunięte przed wersją 3.6.Szybkość można porównać z najszybszą metodą dla Pythona 2, czyli
+
konkatenacją na moim komputerze; a to zajmuje 0,203 µs przy 8-bitowych łańcuchach i 0,259 µs, jeśli wszystkie łańcuchy są Unicode.źródło
To zależy od tego, co robisz.
Po Pythonie 2.5, konkatenacja ciągów znaków z operatorem + jest dość szybka. Jeśli łączysz tylko kilka wartości, najlepiej działa operator +:
Jeśli jednak składasz łańcuch w pętli, lepiej jest użyć metody łączenia list:
... ale zauważ, że musisz złożyć stosunkowo dużą liczbę strun, zanim różnica stanie się zauważalna.
źródło
Zgodnie z odpowiedzią Johna Fouhy'ego, nie optymalizuj, chyba że musisz, ale jeśli jesteś tutaj i zadajesz to pytanie, może to być właśnie dlatego, że musisz . W moim przypadku potrzebowałem złożyć kilka adresów URL ze zmiennych łańcuchowych ... szybko. Zauważyłem, że nikt (jak dotąd) nie rozważał metody formatu ciągów, więc pomyślałem, że spróbuję tego i, głównie ze względu na niewielkie zainteresowanie, pomyślałem, że wrzucę tam operator interpolacji ciągów dla dobrego pomiaru. Szczerze mówiąc, nie sądziłem, że którykolwiek z nich będzie się wiązał z bezpośrednią operacją „+” lub „.join ()”. Ale zgadnij co? W moim systemie Python 2.7.5 operator interpolacji ciągów rządzi wszystkimi, a string.format () jest najgorszy:
Wyniki:
Jeśli użyję krótszej domeny i krótszej ścieżki, nadal wygrywa interpolacja. Różnica jest jednak wyraźniejsza w przypadku dłuższych sznurków.
Teraz, gdy miałem ładny skrypt testowy, testowałem również pod Pythonem 2.6, 3.3 i 3.4, oto wyniki. W Pythonie 2.6 operator plus jest najszybszy! W Pythonie 3 dołączanie wygrywa. Uwaga: te testy są bardzo powtarzalne w moim systemie. Tak więc „plus” jest zawsze szybszy w 2.6, „intp” jest zawsze szybszy w 2.7, a „join” jest zawsze szybszy w Pythonie 3.x.
Wyciągnięta lekcja:
tl; dr:
źródło
f'http://{domain}/{lang}/{path}'
.format()
ma trzy formy, w kolejności od szybkiego do wolnego:"{}".format(x)
,"{0}".format(x)
,"{x}".format(x=x)
w dużej mierze zależy to od względnych rozmiarów nowego łańcucha po każdym nowym połączeniu. Za pomocą
+
operatora dla każdego konkatenacji tworzony jest nowy łańcuch. Jeśli ciągi pośredniczące są stosunkowo długie,+
stają się coraz wolniejsze, ponieważ nowy ciąg pośredni jest przechowywany.Rozważ ten przypadek:
Wyniki
1 0,00493192672729
2 0.000509023666382
3 0.00042200088501
4 0.000482797622681
W przypadku 1 & 2 dodajemy duży ciąg i funkcja join () działa około 10 razy szybciej. W przypadku 3 i 4 dodajemy mały ciąg i znak „+” działa nieco szybciej
źródło
Znalazłem się w sytuacji, w której potrzebowałem dołączyć ciąg o nieznanym rozmiarze. Oto wyniki testów porównawczych (python 2.7.3):
To wydaje się wskazywać, że najszybszy jest znak „+ =”. Wyniki z linku Skymind są nieco nieaktualne.
(Zdaję sobie sprawę, że drugi przykład nie jest kompletny, ostateczna lista musiałaby zostać połączona. To jednak pokazuje, że samo przygotowanie listy trwa dłużej niż konkatowanie ciągów).
źródło
Rok później przetestujmy odpowiedź mkoistinena w Pythonie 3.4.3:
Nic się nie zmieniło. Łączenie jest nadal najszybszą metodą. Ponieważ intp jest prawdopodobnie najlepszym wyborem pod względem czytelności, mimo wszystko możesz chcieć użyć intp.
źródło
Zainspirowany testami porównawczymi @ JasonBaker, oto prosty test porównujący 10
"abcdefghijklmnopqrstuvxyz"
strun, pokazujący, że.join()
jest szybszy; nawet przy tak niewielkim wzroście zmiennych:Wiązanie
Przystąp
źródło
Dla małego zestawu z krótkich ciągów (czyli 2 lub 3 struny nie więcej niż kilka znaków), oraz jest jeszcze szybsza. Korzystanie ze wspaniałego skryptu mkoistinen w Pythonie 2 i 3:
Więc kiedy twój kod wykonuje ogromną liczbę oddzielnych małych konkatenacji, plus jest preferowanym sposobem, jeśli szybkość ma kluczowe znaczenie.
źródło
Prawdopodobnie „nowe f-stringi w Pythonie 3.6” to najbardziej efektywny sposób łączenia łańcuchów.
Używając% s
Korzystanie z .format
Korzystanie f
Źródło: https://realpython.com/python-f-strings/
źródło