W Pythonie umyka mi to, gdzie i kiedy używać łączenia ciągów w porównaniu z zastępowaniem ciągów. Ponieważ konkatenacja strun spowodowała duży wzrost wydajności, czy jest to (staje się coraz bardziej) decyzją stylistyczną, a nie praktyczną?
Na konkretny przykład, jak należy obsłużyć tworzenie elastycznych identyfikatorów URI:
DOMAIN = 'http://stackoverflow.com'
QUESTIONS = '/questions'
def so_question_uri_sub(q_num):
return "%s%s/%d" % (DOMAIN, QUESTIONS, q_num)
def so_question_uri_cat(q_num):
return DOMAIN + QUESTIONS + '/' + str(q_num)
Edycja: Pojawiły się również sugestie dotyczące dołączania do listy ciągów i używania nazwanych podstawień. To są warianty dotyczące głównego tematu, czyli: w jaki sposób należy to zrobić w jakim czasie? Dzięki za odpowiedzi!
python
string
string-concatenation
gotgenes
źródło
źródło
Odpowiedzi:
Według mojego komputera konkatenacja jest (znacznie) szybsza. Ale stylistycznie jestem gotów zapłacić cenę zastąpienia, jeśli wydajność nie jest krytyczna. Cóż, a jeśli potrzebuję formatowania, nie ma potrzeby nawet zadawać pytania ... nie ma innego wyjścia, jak tylko użyć interpolacji / szablonów.
źródło
Nie zapomnij o nazwanym podstawieniu:
źródło
Uważaj na łączenie ciągów w pętli! Koszt konkatenacji ciągów znaków jest proporcjonalny do długości wyniku. Pętla prowadzi prosto do krainy N-kwadrat. Niektóre języki optymalizują konkatenację do ostatnio przydzielonego ciągu, ale ryzykowne jest liczenie na kompilator, który zoptymalizuje algorytm kwadratowy do liniowego. Najlepiej używać prymitywu (
join
?), Który pobiera całą listę ciągów, wykonuje jedną alokację i łączy je wszystkie za jednym razem.źródło
„Ponieważ konkatenacja strun spowodowała duży wzrost wydajności ...”
Jeśli wydajność ma znaczenie, dobrze jest wiedzieć.
Jednak problemy z wydajnością, które widziałem, nigdy nie sprowadzały się do operacji na łańcuchach. Generalnie mam problemy z operacjami I / O, sortowaniem i O ( n 2 ), które stanowią wąskie gardła.
Dopóki operacje na strunach nie ograniczą wydajności, będę się trzymać rzeczy oczywistych. Przeważnie jest to podstawienie, gdy jest to jedna linia lub mniej, konkatenacja, gdy ma to sens, i narzędzie szablonu (takie jak Mako), gdy jest duże.
źródło
To, co chcesz połączyć / interpolować i jak chcesz sformatować wynik, powinno wpłynąć na twoją decyzję.
Interpolacja ciągów umożliwia łatwe dodawanie formatowania. W rzeczywistości twoja wersja z interpolacją ciągów nie robi tego samego, co twoja wersja z konkatenacją; w rzeczywistości dodaje dodatkowy ukośnik przed
q_num
parametrem. Aby zrobić to samo, musiałbyś napisaćreturn DOMAIN + QUESTIONS + "/" + str(q_num)
w tym przykładzie.Interpolacja ułatwia formatowanie liczb;
"%d of %d (%2.2f%%)" % (current, total, total/current)
byłby znacznie mniej czytelny w formie konkatenacji.Konkatenacja jest przydatna, gdy nie masz ustalonej liczby elementów do zestrojenia.
Wiedz też, że Python 2.6 wprowadza nową wersję interpolacji ciągów, zwaną szablonami ciągów :
Tworzenie szablonów łańcuchów ma ostatecznie zastąpić interpolację%, ale myślę, że to nie nastąpi przez dłuższy czas.
źródło
Właśnie testowałem szybkość różnych metod łączenia / zastępowania ciągów z ciekawości. Wyszukiwarka google na ten temat przywiodła mnie tutaj. Pomyślałem, że opublikuję wyniki moich testów w nadziei, że to pomoże komuś zdecydować.
... Po uruchomieniu
runtests((percent_, format_, format2_, concat_), runs=5)
zauważyłem, że metoda% była około dwa razy szybsza niż inne na tych małych strunach. Metoda concat była zawsze najwolniejsza (ledwo). Wystąpiły bardzo drobne różnice podczas zmiany pozycji wformat()
metodzie, ale zmiana pozycji była zawsze co najmniej 0,01 wolniejsza niż w przypadku metody standardowego formatu.Przykładowe wyniki badań:
Uruchomiłem je, ponieważ używam konkatenacji ciągów w moich skryptach i zastanawiałem się, jaki jest koszt. Uruchomiłem je w różnych kolejności, aby upewnić się, że nic nie przeszkadza lub uzyskuje lepszą wydajność jako pierwszy lub ostatni. Na marginesie, do tych funkcji
"%s" + ("a" * 1024)
dodałem kilka dłuższych generatorów ciągów, a zwykłe konkatowanie było prawie 3 razy szybsze (1,1 vs 2,8) niż przy użyciu metodformat
i%
. Myślę, że to zależy od strun i tego, co próbujesz osiągnąć. Jeśli wydajność naprawdę ma znaczenie, lepiej spróbować różnych rzeczy i je przetestować. Zwykle przedkładam czytelność zamiast szybkości, chyba że szybkość stanie się problemem, ale to tylko ja. Więc nie podobało mi się moje kopiowanie / wklejanie, musiałem umieścić 8 spacji na wszystkim, aby wyglądało dobrze. Zwykle używam 4.źródło
str.format()
istr.join()
na normalnym konkatenacji. Zwracam też uwagę na „f-strings” z PEP 498 , który został niedawno zaakceptowany. Jeśli chodzi ostr()
połączenia wpływające na wydajność, jestem pewien, że masz rację. Nie miałem wtedy pojęcia, jak drogie były wywołania funkcji w tamtym czasie. Nadal uważam, że testy należy wykonywać, gdy są jakiekolwiek wątpliwości.join_(): return ''.join(["test ", str(1), ", with number ", str(2)])
, wydaje się, żejoin
jest wolniejszy niż procent.Pamiętaj, decyzje stylistyczne są decyzjami praktycznymi, jeśli kiedykolwiek planujesz utrzymywać lub debugować swój kod :-) Znany cytat Knutha (prawdopodobnie cytując Hoare'a?): „Powinniśmy zapomnieć o małych wydajnościach, powiedzmy w 97% przypadków: przedwczesna optymalizacja jest źródłem wszelkiego zła ”.
Tak długo, jak uważasz, aby (powiedzieć) nie zamieniać zadania O (n) w zadanie O (n 2 ), wybrałbym to, co uznasz za najłatwiejsze do zrozumienia.
źródło
Stosuję substytucję, gdzie tylko mogę. Używam konkatenacji tylko wtedy, gdy buduję łańcuch w, powiedzmy, pętli for.
źródło
Właściwie właściwą rzeczą do zrobienia w tym przypadku (budowanie ścieżek) jest użycie
os.path.join
. Nie konkatenacja ciągów ani interpolacjaźródło