Клас струн Python, як StringBuilder в C #?


121

Чи є якийсь клас струн у Python, як StringBuilderу C #?


6
Це дублікат еквівалента Python Java StringBuffer . ПОПЕРЕДЖЕННЯ: Відповіді тут застарілі і фактично стають оманливими. Дивіться інше запитання щодо відповідей, більш актуальних для сучасних версій Python (безумовно, 2.7 і вище).
Жан-Франсуа Корбетт

Відповіді:


102

Не існує співвідношення один на один. По-справжньому гарну статтю див. У розділі Ефективне об'єднання рядків у Python :

Побудова довгих рядків на мові прогмінгу Python іноді може призвести до дуже повільного запущеного коду. У цій статті я досліджую обчислювальну ефективність різних методів конкатенації рядків.


27
Зауважте, що ця стаття була написана на основі Python 2.2. Тести, ймовірно, вийдуть дещо інакше в сучасній версії Python (CPython зазвичай успішно оптимізує конкатенацію, але ви не хочете залежати від цього у важливому коді) і вираження генератора, де він використовує розуміння списку, було б заслуговувати на розгляд .
Майк Грехем

4
Було б добре висвітлити деякі основні моменти цієї статті, принаймні, пару реалізацій (щоб уникнути проблем з гниттю зв’язку).
jpmc26

3
Спосіб 1: resultString + = appendString є найшвидшим за результатами тестів @ Antoine-tran нижче
Justas

5
Ваша цитата зовсім не відповідає на запитання. Будь ласка, включіть у свою відповідь відповідні частини, щоб відповідати новим вказівкам.
Фонд позову Моніки

27

Я використав код Олівера Кроу (посилання, яке надав Ендрю Заєць) і трохи адаптував його до адаптації Python 2.7.3. (за допомогою пакету timeit). Я працював на своєму персональному комп’ютері, Lenovo T61, 6 Гб оперативної пам’яті, Debian GNU / Linux 6.0.6 (стискати).

Ось результат для 10000 ітерацій:

метод1: 0,0538418292999 сек
розмір процесу 4800 кб
метод2: 0,22602891922 сек
розмір процесу 4960 кб
метод3: 0,0605459213257 сек
розмір процесу 4980 кб
метод4: 0,05404030666351 сек
розмір процесу 5536 кб
метод5: 0,051080703735 сек
розмір процесу 5272 кб
метод6: 0,0542731285095 сек
розмір процесу 5512 кб

і для 5 000 000 ітерацій (метод 2 був ігнорований, оскільки він запускався занадто повільно, як назавжди):

метод1: 5.88603997231 сек
розмір процесу 37976 кб
метод3: 8.40748500824 сек
розмір процесу 38024 кб
метод4: 7.96380496025 сек
розмір процесу 321968 кб
метод5: 8.03666186333 сек
розмір процесу 71720 кб
метод6: 6.68192911148 сек
розмір процесу 38240 кб

Цілком очевидно, що хлопці з Python зробили досить велику роботу з оптимізації конкатенації рядків, і, як сказав Хоар: "передчасна оптимізація - корінь усього зла" :-)


2
Мабуть, Хоаре не приймає цього: hans.gerwitz.com/2004/08/12/…
Пімін Костянтин Кефалукос

5
Це не передчасна оптимізація, щоб уникнути неміцних, залежних від перекладачів оптимізацій. Якщо ви хочете коли-небудь перенести порт на PyPy або ризикуєте потрапити в один із безлічі тонких випадків відмови для оптимізації, зробіть все правильно.
Ведрак

1
Схоже, метод 1 простіший для компілятора оптимізувати.
mbomb007

25

Покладатися на оптимізацію компілятора неміцно. Орієнтирам, пов'язаним у прийнятій відповіді, та цифри, надані Антуаном-тран, не варто вірити. Ендрю Заєць робить помилку, включаючи заклик до reprсвоїх методів. Це сповільнює всі методи однаково, але затьмарює реальну кару при побудові рядка.

Використовуйте join. Це дуже швидко і надійніше.

$ 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

Так, reprвиклик домінує під час виконання, але не потрібно робити помилку особистою.
Алекс Рейнкінг

3
@AlexReinking вибачте, нічого особистого не означало. Я не впевнений, що змусило вас думати, що це особисте. Але якщо це було використання їх імен, я використовував їх лише для позначення відповідей користувача (відповідає іменам користувачів, не впевнений, чи є кращий спосіб).
GrantJ

1
хороший приклад синхронізації, який розділяє операції ініціалізації та конкатенації даних
aiodintsov

19

У Python є кілька речей, які відповідають подібним цілям:

  • Одним із поширених способів побудови великих рядків із шматочків є створення списку рядків та приєднання до нього, коли ви закінчите. Це часто використовувана ідіома Python.
    • Щоб створити рядки, що містять дані з форматуванням, ви б виконали форматування окремо.
  • Для вставки та видалення на рівні символів ви б зберігали список рядків довжиною-одна. (Щоб зробити це з рядка, ви б зателефонували list(your_string). Ви також можете використовувати UserString.MutableStringдля цього.
  • (c)StringIO.StringIO корисно для речей, які б інакше взяли файл, але менш для загальної побудови рядків.

10

Використовуючи метод 5 зверху (The Pseudo File), ми можемо отримати дуже хороший перф і гнучкість

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()

тепер його використовуємо

sb = StringBuilder()

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

print sb


-1

Немає явного аналога - я думаю, від вас очікується використання рядкових конкатенацій (швидше за все, оптимізованих, як було сказано раніше) або сторонніх класів (я сумніваюся, що вони набагато ефективніші - списки в python мають динамічний тип, тому немає швидкодіючих char [] для буфера, як я припускаю). Класи, схожі на Stringbuilder, не мають передчасної оптимізації через вроджену особливість рядків на багатьох мовах (незмінність) - що дозволяє здійснити багато оптимізацій (наприклад, посилання на той самий буфер для фрагментів / підрядів). Класи Stringbuilder / stringbuffer / stringstream працюють набагато швидше, ніж об'єднання рядків (створюючи багато невеликих тимчасових об'єктів, які все ще потребують виділення та збирання сміття) і навіть форматування рядків інструментів, схожих на printf, не потребують інтерпретації накладних форм форматування, які досить затратні для багато форматних дзвінків.


-4

Якщо ви шукаєте тут метод швидкого з'єднання рядків у Python, то вам не потрібен спеціальний клас StringBuilder. Просте конкатенація працює так само без покарання за ефективність, яке бачимо на C #.

resultString = ""

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

Дивіться відповідь Антуана-тран за результатами роботи

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.