Typowym antywzorem w Pythonie jest konkatenacja sekwencji ciągów za +
pomocą pętli. Jest to złe, ponieważ interpreter Pythona musi utworzyć nowy obiekt łańcuchowy dla każdej iteracji, co w rezultacie zajmuje czas kwadratowy. (Najnowsze wersje CPythona mogą najwyraźniej optymalizować to w niektórych przypadkach, ale inne implementacje nie mogą, więc programistów odradza się polegać na tym.) ''.join
Jest właściwym sposobem zrobienia tego.
Jednak słyszałem, jak powiedziano (w tym tutaj na Stack Overflow ), że nigdy, przenigdy nie powinieneś używać +
do łączenia ciągów, ale zamiast tego zawsze używaj ''.join
lub ciągu formatującego. Nie rozumiem, dlaczego tak się dzieje, jeśli łączysz tylko dwa ciągi. Jeśli moje rozumienie jest poprawne, nie powinno to zająć czasu kwadratowego i myślę, że a + b
jest bardziej przejrzyste i czytelne niż jedno ''.join((a, b))
lub drugie '%s%s' % (a, b)
.
Czy jest dobrą praktyką +
łączenie dwóch ciągów? A może jest problem, którego nie jestem świadomy?
+
jest szybszy czy wolniejszy? I dlaczego?In [2]: %timeit "a"*80 + "b"*80
1000000 loops, best of 3: 356 ns per loop
In [3]: %timeit "%s%s" % ("a"*80, "b"*80)
1000000 loops, best of 3: 907 ns per loop
In [3]: %timeit "%s%s" % (a, b) 1000000 loops, best of 3: 590 ns per loop
In [4]: %timeit a + b 10000000 loops, best of 3: 147 ns per loop
__str__
. Zobacz moją odpowiedź na przykłady.Odpowiedzi:
Nie ma nic złego w łączeniu dwóch ciągów z
+
. Rzeczywiście, łatwiej to czytać niż''.join([a, b])
.Masz jednak rację, że łączenie więcej niż 2 ciągów za pomocą
+
jest operacją O (n ^ 2) (w porównaniu do O (n) forjoin
) i przez to staje się nieefektywne. Nie ma to jednak nic wspólnego z używaniem pętli. Parzystośća + b + c + ...
to O (n ^ 2), a powodem jest to, że każda konkatenacja tworzy nowy ciąg.CPython2.4 i nowsze starają się to złagodzić, ale nadal zaleca się używanie
join
podczas łączenia więcej niż 2 ciągów.źródło
.join
przyjmuje iterowalne , więc oba.join([a,b])
i.join((a,b))
są poprawne.+
lub+=
w akceptowanej odpowiedzi (od 2013 r.) Na stackoverflow.com/a/12171382/378826 (z Lennart Regebro) nawet dla CPythona 2.3+ i wybranie wzorca „dołącz / dołącz” tylko wtedy, gdy ten jaśniej ujawnia pomysł na rozwiązanie problemu.Operator Plus jest idealnym rozwiązaniem do łączenia dwóch ciągów języka Python. Ale jeśli będziesz dodawać więcej niż dwa ciągi (n> 25), możesz pomyśleć o czymś innym.
''.join([a, b, c])
sztuczka polega na optymalizacji wydajności.źródło
append()
łańcuchów do listy.n > 25
. Ludzie potrzebują punktów odniesienia, aby od czegoś zacząć.Założenie, że nigdy, przenigdy nie powinno się używać znaku + do konkatenacji ciągów, ale zamiast tego zawsze używać '' .join, może być mitem. Prawdą jest, że using
+
tworzy niepotrzebne tymczasowe kopie niezmiennego obiektu string, ale innym nieczęsto cytowanym faktem jest to, że wywołaniejoin
pętli generalnie spowodowałoby dodanie narzutufunction call
. Weźmy przykład.Utwórz dwie listy, jedną z połączonego pytania SO, a drugą, większą, utworzoną
Pozwala tworzyć dwie funkcje,
UseJoin
iUsePlus
używać odpowiednijoin
i+
funkcjonalność.Pozwala uruchomić timeit z pierwszą listą
Mają prawie taki sam czas działania.
Użyjmy cProfile
Wygląda na to, że użycie Join powoduje niepotrzebne wywołania funkcji, które mogą zwiększyć narzut.
A teraz wracając do pytania. Czy we wszystkich przypadkach należy zniechęcać do używania
+
overjoin
?Uważam, że nie, należy wziąć pod uwagę
A poza tym w rozwoju przedwczesnej optymalizacji jest zła.
źródło
join
wewnątrz samej pętli - raczej pętla generowałaby sekwencję, która byłaby przekazywana do połączenia.Podczas pracy z wieloma osobami czasami trudno jest dokładnie wiedzieć, co się dzieje. Użycie ciągu formatu zamiast konkatenacji może uniknąć jednej konkretnej irytacji, która zdarzała się nam mnóstwo razy:
Powiedzmy, funkcja wymaga argumentu i piszesz ją, oczekując otrzymania łańcucha:
Tak więc ta funkcja może być używana dość często w całym kodzie. Twoi współpracownicy mogą dokładnie wiedzieć, co robi, ale niekoniecznie są w pełni na bieżąco z elementami wewnętrznymi i mogą nie wiedzieć, że funkcja oczekuje łańcucha. I tak mogą skończyć się tym:
Nie byłoby problemu, gdybyś użył tylko ciągu formatu:
To samo dotyczy wszystkich typów obiektów, które definiują
__str__
, które również można przekazać:Więc tak: jeśli możesz użyć ciągu formatu, zrób to i wykorzystaj to, co ma do zaoferowania Python.
źródło
+
choć.zeta = u"a\xac\u1234\u20ac\U00008000"
- musisz użyć,print 'bar: ' + unicode(zeta)
aby upewnić się, że nie zawiera błędów.%s
robi to dobrze, nie myśląc o tym, i jest znacznie krótszy"bar: %s"
mogą być przetłumaczone na"zrb: %s br"
inny język.%s
Wersja będzie tylko praca, ale wersja string-concat stałaby się bałagan obsłużyć wszystkie przypadki i tłumacze będą teraz dwa oddzielne tłumaczenia do czynienia zdef
.Zrobiłem szybki test:
i zaplanowałem to:
Najwyraźniej istnieje optymalizacja dla
a = a + b
przypadku. Nie wykazuje czasu O (n ^ 2), jak można by przypuszczać.Tak więc, przynajmniej pod względem wydajności, używanie
+
jest w porządku.źródło
Według dokumentacji Pythona, użycie str.join () zapewni spójność wydajności w różnych implementacjach Pythona. Chociaż CPython optymalizuje kwadratowe zachowanie s = s + t, inne implementacje Pythona mogą tego nie robić.
Typy sekwencji w dokumentach Pythona (zobacz przypis [6])
źródło
Używam następujących z Pythonem 3.8
źródło
'' .join ([a, b]) jest lepszym rozwiązaniem niż + .
Ponieważ kod powinien być napisany w sposób, który nie szkodzi innym implementacjom Pythona (PyPy, Jython, IronPython, Cython, Psyco i tym podobnych)
form a + = b lub a = a + b jest krucha nawet w CPythonie i nie występuje w ogóle w implementacjach , które nie używają refcounting (liczenie referencji to technika przechowywania liczby referencji, wskaźników lub uchwytów do a zasób, taki jak obiekt, blok pamięci, miejsce na dysku lub inny zasób )
https://www.python.org/dev/peps/pep-0008/#programming-recommendations
źródło
a += b
działa we wszystkich implementacjach Pythona, po prostu na niektórych z nich zajmuje to kwadratowy czas, gdy wykonuje się je wewnątrz pętli ; pytanie dotyczyło konkatenacji ciągów poza pętlą.