2010-03-10 11 views
70

Czy istnieje klasa napisów w języku Python, np. StringBuilder w języku C#?Python ciąg klasy jak StringBuilder w C#?

+1

To jest duplikat [odpowiednik Java StringBuffer w języku Python] (https://stackoverflow.com/questions/19926089/python-equivalent-of-java-stringbuffer). ** UWAGA: Odpowiedzi są tu nieaktualne i w rzeczywistości stają się mylące. ** Zobacz [to inne pytanie] (https://stackoverflow.com/questions/19926089/python-equivalent-of-java- stringbuffer) dla odpowiedzi, które są bardziej odpowiednie dla współczesnych wersji Pythona (z pewnością 2.7 i wyżej). –

Odpowiedz

58

nie ma korelacji jeden-do-jednego. Do bardzo dobry artykuł można znaleźć Efficient String Concatenation in Python:

Budowanie długich ciągów w języku Python progamming może czasami wynik w bardzo powolnym kod uruchomiony. W artykule w tym artykule badam wydajność obliczeniową różnych metod łączenia ciągów znaków .

+14

Należy zauważyć, że ten artykuł został napisany w oparciu o Python 2.2. Testy najprawdopodobniej wyjdą nieco inaczej w nowoczesnej wersji Pythona (CPython zazwyczaj z powodzeniem optymalizuje konkatenację, ale nie chcesz polegać na tym w ważnym kodzie), a wyrażenie generujące, w którym używa on listy, byłoby warte rozważenia . –

+3

Byłoby dobrze wciągnąć w ten artykuł kilka najciekawszych momentów, przynajmniej kilka implementacji (aby uniknąć problemów z rotowaniem linków). – jpmc26

+3

Metoda 1: resultString + = appendString jest najszybszy według testów @ Antoine-tran poniżej – Justas

12

Python ma kilka rzeczy, które spełniają podobne cele:

  • jeden wspólny sposób budowania dużych ciągów kawałków wzrośnie listę ciągów i dołącz go, gdy skończysz. Jest to często używany idiom Pythona.
    • Aby zbudować ciągi zawierające dane z formatowaniem, należy zrobić to oddzielnie.
  • Aby wstawić i usunąć na poziomie postaci, należy zachować listę długości-jeden ciąg. (Aby to z ciągiem, można by nazwać list(your_string). Można też użyć UserString.MutableString do tego.
  • (c)StringIO.StringIO jest przydatna dla rzeczy, które w przeciwnym razie byłoby wziąć plik, ale mniej dla budownictwa ogólnego strun.
23

Użyłem kodu Olivera Crowa (link podany przez Andrew Hare'a) i zaadaptowałem go trochę, aby dostosować Pythona 2.7.3 (używając pakietu timeit) .Poznałem na moim komputerze, Lenovo T61, 6 GB RAM, Debian GNU/Linux 6.0.6 (squeeze).

Oto wynik dla 10.000 iteracji:

 
method1: 0.0538418292999 secs 
process size 4800 kb 
method2: 0.22602891922 secs 
process size 4960 kb 
method3: 0.0605459213257 secs 
process size 4980 kb 
method4: 0.0544030666351 secs 
process size 5536 kb 
method5: 0.0551080703735 secs 
process size 5272 kb 
method6: 0.0542731285095 secs 
process size 5512 kb 

oraz 5.000.000 iteracji (metoda 2 został zignorowany, ponieważ zabrakło tooo powoli, tak jak zawsze):

 
method1: 5.88603997231 secs 
process size 37976 kb 
method3: 8.40748500824 secs 
process size 38024 kb 
method4: 7.96380496025 secs 
process size 321968 kb 
method5: 8.03666186333 secs 
process size 71720 kb 
method6: 6.68192911148 secs 
process size 38240 kb 

Jest dość oczywiste, że Python chłopaki zrobili bardzo dobrą robotę w celu optymalizacji ciąg konkatenacji, a jak Hoare powiedział: „przedwczesna optymalizacja jest źródłem wszelkiego zła” :-)

+1

Wygląda na to, że Hoare nie akceptuje tego: http://hans.gerwitz.com/2004/08/12/premature-optimization-is-the-root-all-evil.html –

+2

Nie jest to przedwczesna optymalizacja, aby uniknąć kruche, zależne od interpretacji optymalizacje. Jeśli kiedykolwiek chcesz przesłać do PyPy lub ryzykować trafieniem [jednym z wielu przypadków subtelnego niepowodzenia] (http://stackoverflow.com/questions/24040198/cpython-string-addition-optimisation-failure-case) w celu optymalizacji, należy rzeczy we właściwy sposób. – Veedrac

+0

Wygląda na to, że metoda 1 jest łatwiejsza do optymalizacji przez kompilator. – mbomb007

8

stosując metodę 5 od góry (plik pseudo) możemy uzyskać bardzo dobre perf i elastyczność

from cStringIO import StringIO 

class StringBuilder: 
    _file_str = None 

    def __init__(self): 
     self._file_str = StringIO() 

    def Append(self, str): 
     self._file_str.write(str) 

    def __str__(self): 
     return self._file_str.getvalue() 

teraz używając go

sb = StringBuilder() 

sb.Append("Hello\n") 
sb.Append("World") 

print sb 
-1

W przypadku, gdy jesteś tutaj szukasz szybki sposób ciąg konkatenacji w Pythonie, wtedy nie trzeba specjalnej klasy StringBuilder. Prosta konkatenacja działa równie dobrze bez kary wydajności widzianej w C#.

resultString = "" 

resultString += "Append 1" 
resultString += "Append 2" 

Zobacz Antoine-tran's answer wyników dla

5

Powołując się na optymalizacje kompilatora jest krucha wydajność. Punktów odniesienia powiązanych z zaakceptowaną odpowiedzią i liczbami podanymi przez Antoine-tran nie należy ufać. Andrew Hare popełnia błąd polegający na tym, że w jego metodach został zawarty numer repr. To spowalnia wszystkie metody jednakowo, ale zasłania rzeczywistą karę w konstruowaniu struny.

Użyj join. Jest bardzo szybki i niezawodny.

$ ipython3 
Python 3.5.1 (default, Mar 2 2016, 03:38:02) 
IPython 4.1.2 -- An enhanced Interactive Python. 

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 
0

Nie ma wyraźnego analogowe - myślę, że oczekuje się, aby użyć powiązań, String (najprawdopodobniej zoptymalizowane jak powiedziałem wcześniej) lub klasa osób trzecich (wątpię, że są one dużo bardziej wydajny - list w Pythonie są dynamiczne -typed więc bez szybkiego działania char [] dla bufora, jak zakładam). Klasy podobne do Stringbuildera nie są przedwczesną optymalizacją ze względu na wrodzoną funkcję łańcuchó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). Klasa Stringbuilder/stringbuffer/stringstream-like działa dużo szybciej niż konkatenacja łańcuchów (generowanie wielu małych tymczasowych obiektów, które wciąż wymagają alokacji i usuwania śmieci), a nawet formatowanie narzędzi podobnych do printf, bez potrzeby interpretowania narzutów związanych z formatowaniem, które są dość pochłaniające dla wielu połączeń formatujących.