To jest duplikat odpowiednika Java StringBuffer w Pythonie . OSTRZEŻENIE: Odpowiedzi tutaj są nieaktualne i faktycznie stały się mylące. Zobacz to inne pytanie, aby uzyskać odpowiedzi, które są bardziej odpowiednie dla współczesnych wersji Pythona (z pewnością 2.7 i nowszych).
Budowanie długich ciągów w języku programowania Python może czasami skutkować bardzo powolnym działaniem kodu. W tym artykule badam wydajność obliczeniową różnych metod łączenia ciągów.
Zauważ, że ten artykuł został napisany w oparciu o Python 2.2. Testy prawdopodobnie wypadłyby nieco inaczej w nowoczesnej wersji Pythona (CPython zwykle z powodzeniem optymalizuje konkatenację, ale nie chcesz na tym polegać w ważnym kodzie) i wyrażenie generatora, w którym używa rozumienia listy, byłoby warte rozważenia .
Mike Graham
4
Byłoby dobrze wyciągnąć kilka najważniejszych informacji z tego artykułu, przynajmniej kilka implementacji (aby uniknąć problemów z gniciem linków).
jpmc26
3
Metoda 1: resultString + = appendString jest najszybszy zgodnie z testami @ Antoine-tran poniżej
Justas
5
Twoja wycena w ogóle nie odpowiada na pytanie. Prosimy o uwzględnienie odpowiednich części w samej odpowiedzi, aby zachować zgodność z nowymi wytycznymi.
Załóż pozew Moniki z
27
Użyłem kodu Olivera Crow'a (link podany przez Andrew Hare'a) i dostosowałem go trochę, aby dostosować Python 2.7.3. (przy użyciu pakietu timeit). Uruchomiłem na swoim komputerze osobistym Lenovo T61, 6 GB RAM, Debian GNU / Linux 6.0.6 (squeeze).
Oto wynik dla 10000 iteracji:
metoda1: 0,0538418292999 sek
wielkość procesu 4800 kb
metoda2: 0,22602891922 sek
wielkość procesu 4960 kb
metoda3: 0,0605459213257 sek
wielkość procesu 4980 kb
metoda4: 0,0544030666351 sek
wielkość procesu 5536 kb
metoda5: 0,0551080703735 sek
wielkość procesu 5272 kb
metoda6: 0,0542731285095 sek
wielkość procesu 5512 kb
i dla 5 000 000 iteracji (metoda 2 została zignorowana, ponieważ działała zbyt wolno, jak zawsze):
metoda1: 5,88603997231 sek
wielkość procesu 37976 kb
metoda3: 8.40748500824 sek
wielkość procesu 38024 kb
metoda4: 7,96380496025 sek
wielkość procesu 321968 kb
metoda5: 8,03666186333 sek
wielkość procesu 71720 kb
metoda6: 6,68192911148 sek
wielkość procesu 38240 kb
Jest całkiem oczywiste, że ludzie z Pythona wykonali kawał dobrej roboty, aby zoptymalizować konkatenację ciągów i jak powiedział Hoare: „przedwczesna optymalizacja jest źródłem wszelkiego zła” :-)
Nie jest to przedwczesna optymalizacja, aby uniknąć kruchych optymalizacji zależnych od interpretera. Jeśli kiedykolwiek chcesz przenieść się do PyPy lub zaryzykować jeden z wielu subtelnych przypadków niepowodzenia optymalizacji, zrób to we właściwy sposób.
Veedrac
1
Wygląda na to, że metoda 1 jest łatwiejsza do optymalizacji dla kompilatora.
mbomb007
25
Poleganie na optymalizacji kompilatora jest delikatne. Nie należy ufać benchmarkom podanym w zaakceptowanej odpowiedzi i liczbom podanym przez Antoine-tran. Andrew Hare popełnia błąd, włączając wywołanie do reprswoich metod. To jednakowo spowalnia wszystkie metody, ale przesłania prawdziwą karę w tworzeniu łańcucha.
Użyj join. Jest bardzo szybki i solidniejszy.
$ ipython3
Python3.5.1(default,Mar22016,03:38:02)IPython4.1.2--An enhanced InteractivePython.In[1]: values =[str(num)for num in range(int(1e3))]In[2]:%%timeit
...:''.join(values)...:100000 loops, best of 3:7.37µs per loop
In[3]:%%timeit
...: result =''...:for value in values:...: result += value
...:10000 loops, best of 3:82.8µs per loop
In[4]:import io
In[5]:%%timeit
...: writer = io.StringIO()...:for value in values:...: writer.write(value)...: writer.getvalue()...:10000 loops, best of 3:81.8µs per loop
Tak, reprpołączenie dominuje w czasie wykonywania, ale nie ma potrzeby, aby ten błąd był osobisty.
Alex Reinking
3
@AlexReinking przepraszam, nic osobistego nie znaczyło. Nie jestem pewien, co sprawiło, że pomyślałeś, że to sprawa osobista. Ale jeśli chodziło o użycie ich nazw, użyłem ich tylko do odniesienia się do odpowiedzi użytkowników (dopasowuje nazwy użytkowników, nie jestem pewien, czy jest lepszy sposób).
GrantJ
1
dobry przykład synchronizacji, który oddziela operacje inicjalizacji i konkatenacji danych
aiodintsov
19
Python ma kilka rzeczy, które spełniają podobne cele:
Jednym z powszechnych sposobów budowania dużych strun z kawałków jest utworzenie listy strun i dołączenie do niej, gdy skończysz. To jest często używany idiom w Pythonie.
Aby zbudować ciągi zawierające dane z formatowaniem, należy wykonać formatowanie oddzielnie.
W przypadku wstawiania i usuwania na poziomie znaku należy zachować listę ciągów o długości jeden. (Aby zrobić to z łańcucha, powinieneś zadzwonić list(your_string). Możesz także użyć UserString.MutableStringdo tego.
(c)StringIO.StringIO jest przydatny do rzeczy, które w innym przypadku zajęłyby plik, ale mniej do ogólnego budowania ciągów.
Nie ma wyraźnego odpowiednika - myślę, że oczekuje się od Ciebie użycia konkatenacji ciągów (prawdopodobnie zoptymalizowanych, jak wspomniano wcześniej) lub klasy innej firmy (wątpię, czy są o wiele bardziej wydajne - listy w Pythonie są typowane dynamicznie, więc nie działają szybko char [] dla bufora, jak zakładam). Klasy typu Stringbuilder nie są przedwczesną optymalizacją ze względu na wrodzoną cechę ciągów w wielu językach (niezmienność) - która pozwala na wiele optymalizacji (na przykład odwoływanie się do tego samego bufora dla wycinków / podciągów). Klasy typu stringbuilder / stringbuffer / stringstream działają znacznie szybciej niż łączenie ciągów (tworząc wiele małych tymczasowych obiektów, które nadal wymagają alokacji i czyszczenia pamięci), a nawet formatowania ciągów narzędzi podobnych do printf, bez konieczności interpretowania narzutu formatowania wzorca, który jest dość pochłaniający wiele wywołań formatów.
Jeśli szukasz szybkiej metody konkatenacji ciągów znaków w Pythonie, nie potrzebujesz specjalnej klasy StringBuilder. Prosta konkatenacja działa równie dobrze bez obniżenia wydajności widocznego w C #.
Odpowiedzi:
Nie ma korelacji jeden do jednego. Aby uzyskać naprawdę dobry artykuł, zobacz Efektywne konkatenowanie ciągów w Pythonie :
źródło
Użyłem kodu Olivera Crow'a (link podany przez Andrew Hare'a) i dostosowałem go trochę, aby dostosować Python 2.7.3. (przy użyciu pakietu timeit). Uruchomiłem na swoim komputerze osobistym Lenovo T61, 6 GB RAM, Debian GNU / Linux 6.0.6 (squeeze).
Oto wynik dla 10000 iteracji:
i dla 5 000 000 iteracji (metoda 2 została zignorowana, ponieważ działała zbyt wolno, jak zawsze):
Jest całkiem oczywiste, że ludzie z Pythona wykonali kawał dobrej roboty, aby zoptymalizować konkatenację ciągów i jak powiedział Hoare: „przedwczesna optymalizacja jest źródłem wszelkiego zła” :-)
źródło
Poleganie na optymalizacji kompilatora jest delikatne. Nie należy ufać benchmarkom podanym w zaakceptowanej odpowiedzi i liczbom podanym przez Antoine-tran. Andrew Hare popełnia błąd, włączając wywołanie do
repr
swoich metod. To jednakowo spowalnia wszystkie metody, ale przesłania prawdziwą karę w tworzeniu łańcucha.Użyj
join
. Jest bardzo szybki i solidniejszy.źródło
repr
połączenie dominuje w czasie wykonywania, ale nie ma potrzeby, aby ten błąd był osobisty.Python ma kilka rzeczy, które spełniają podobne cele:
list(your_string)
. Możesz także użyćUserString.MutableString
do tego.(c)StringIO.StringIO
jest przydatny do rzeczy, które w innym przypadku zajęłyby plik, ale mniej do ogólnego budowania ciągów.źródło
Używając metody 5 z góry (The Pseudo File) możemy uzyskać bardzo dobrą wydajność i elastyczność
teraz go używam
źródło
możesz wypróbować StringIO lub cStringIO
źródło
Nie ma wyraźnego odpowiednika - myślę, że oczekuje się od Ciebie użycia konkatenacji ciągów (prawdopodobnie zoptymalizowanych, jak wspomniano wcześniej) lub klasy innej firmy (wątpię, czy są o wiele bardziej wydajne - listy w Pythonie są typowane dynamicznie, więc nie działają szybko char [] dla bufora, jak zakładam). Klasy typu Stringbuilder nie są przedwczesną optymalizacją ze względu na wrodzoną cechę ciągów w wielu językach (niezmienność) - która pozwala na wiele optymalizacji (na przykład odwoływanie się do tego samego bufora dla wycinków / podciągów). Klasy typu stringbuilder / stringbuffer / stringstream działają znacznie szybciej niż łączenie ciągów (tworząc wiele małych tymczasowych obiektów, które nadal wymagają alokacji i czyszczenia pamięci), a nawet formatowania ciągów narzędzi podobnych do printf, bez konieczności interpretowania narzutu formatowania wzorca, który jest dość pochłaniający wiele wywołań formatów.
źródło
Jeśli szukasz szybkiej metody konkatenacji ciągów znaków w Pythonie, nie potrzebujesz specjalnej klasy StringBuilder. Prosta konkatenacja działa równie dobrze bez obniżenia wydajności widocznego w C #.
Zobacz odpowiedź Antoine-tran na wyniki wydajności
źródło