Начиная с версии Python'строку s `` может'т быть изменен, мне было интересно, как более эффективно объединить строку?
Я могу написать это:
s += stringfromelsewhere
или такой:
s = []
s.append(somestring)
later
s = ''.join(s)
Пока писал этот вопрос, я нашел хорошую статью про эту тему.
http://www.skymind.com/~ocrow/python_string/
Но это'ы на Python 2.х., так что вопрос было бы что-то изменилось в Python 3?
Лучший способ добавления строки в строковую переменную, чтобы использовать +
или +=
. Это потому, что он'ы читаемым и быстро. Они тоже просто так быстро, что вы выберете-это дело вкуса, последний является наиболее распространенным. Вот тайминги модуль помогите другим`:
a = a + b:
0.11338996887207031
a += b:
0.11040496826171875
Однако, те, кто рекомендуют проводить списков и добавления к ним, а затем соединять эти списки, делать так, потому что добавив строку в список, по-видимому, очень быстро, по сравнению с удлинять строку. И это может быть правдой в некоторых случаях. Вот, например, один миллионов добавляет один символ строки, первые строки, затем к списку:
a += b:
0.10780501365661621
a.append(b):
0.1123361587524414
ОК, получается, что даже если результирующая строка миллион символов, добавляя еще быстрее.
Теперь давайте'ы попробовать с добавлением тысяча символов длинную строку в сто тысяч раз:
a += b:
0.41823482513427734
a.append(b):
0.010656118392944336
Конец строки, следовательно, заканчивает тем, что около 100МБ долго. Это было довольно медленным, добавляя в список был гораздо быстрее. То, что сроки не'т включать в себя финал а.присоединяйтесь к()
. Итак, как долго это займет?
a.join(a):
0.43739795684814453
НУНС. Оказывается, даже в этом случае, добавление/присоединиться медленнее.
Так откуда эта рекомендация взялась? В Python 2?
a += b:
0.165287017822
a.append(b):
0.0132720470428
a.join(a):
0.114929914474
Ну, добавление/соединения незначительно быстрее, если вы используете очень длинные строки (которые вы обычно не'т, что у вас есть строка, что'ы 100мб в памяти?)
Но реальный довод-это Python 2.3. Где я выиграл't даже показать вам время, потому что это's так медленно, что она'т закончил. Эти тесты вдруг возьми минут. За исключением добавления/объединения, которые так же быстро, как при более поздних питоны.
ЮП. Конкатенация строк очень медленно в Python еще в каменном веке. Но на 2.4 это'т больше (или, по крайней мере в Python 2.4.7), поэтому рекомендации для использования присоединить/объединить устарела в 2008 году, когда Python 2.3 перестал обновляться, и вы должны остановить использовать его. :-)
(Обновление: оказывается, когда я делал тестирование более тщательно, что с помощью кнопок +
и + =
- это быстрее для двух строк на Python 2.3, а также. Рекомендации по использованию''.присоединяйтесь к()
должен быть недоразумения)
Однако, это с CPython. Другие реализации могут иметь другие проблемы. И это просто еще одна причина, почему преждевременная оптимизация-это корень всех зол. Дон'т использовать технику, которая'предполагали, что "быстрее" и, если вы не измерить его.
Поэтому в "лучших" по версии сделать конкатенацию строк-использовать + или +=. И если это оказывается медленным для вас, что очень маловероятно, то сделать что-то еще.
Так почему же я использую много дописывать/вступить в мой код? Потому что иногда это'ов на самом деле яснее. Особенно когда все, что вы должны соединить вместе, должны быть разделены пробелами или запятыми или символами новой строки.
Если вы обьединении много значений, то ни. Добавление списка стоит дорого. Вы можете использовать StringIO для этого. Особенно если вы строите его на много операций.
from cStringIO import StringIO
# python3: from io import StringIO
buf = StringIO()
buf.write('foo')
buf.write('foo')
buf.write('foo')
buf.getvalue()
# 'foofoofoo'
Если у вас уже есть полный список вернулся к тебе из какой-то другой операции, затем просто использовать''.присоединиться(Алисат)
Из питона чаво: какой самый эффективный способ для конкатенации строк вместе?
ул. и Байт объекты являются неизменяемыми, поэтому обьединении много струны вместе неэффективен, так как каждый конкатенации создается новый объект. В общем случае, общая стоимость выполнения квадратичного в общая длина строки.
, Чтобы накопить много стр объекты, рекомендуемые фразеологизм, чтобы разместить их в список и вызывать STR.присоединяйтесь() в конце:
ломти = [] для S в my_strings: ломти.добавить(с) В результате = ''.присоединиться(чанки)
(другого достаточно эффективного принято использовать Ио.StringIO)
, Чтобы накопить много байтов объектов, рекомендуемых фразеологизм продлить объект ByteArray с помощью конкатенации (оператор+=):
результат = объект ByteArray() для B в my_bytes_objects: результат += Б
Редактировать: я был глупый и результаты вклеили в обратном направлении, делая его похожим на добавление в список был быстрее, чем cStringIO. Кроме того, я добавил тесты для ByteArray ул./функция concat, а также второй раунд испытаний с использованием большого списка с большими строками. (в Python 2.7.3)
пример оболочкой IPython испытаний для больших списков строк
try:
from cStringIO import StringIO
except:
from io import StringIO
source = ['foo']*1000
%%timeit buf = StringIO()
for i in source:
buf.write(i)
final = buf.getvalue()
# 1000 loops, best of 3: 1.27 ms per loop
%%timeit out = []
for i in source:
out.append(i)
final = ''.join(out)
# 1000 loops, best of 3: 9.89 ms per loop
%%timeit out = bytearray()
for i in source:
out += i
# 10000 loops, best of 3: 98.5 µs per loop
%%timeit out = ""
for i in source:
out += i
# 10000 loops, best of 3: 161 µs per loop
## Repeat the tests with a larger list, containing
## strings that are bigger than the small string caching
## done by the Python
source = ['foo']*1000
# cStringIO
# 10 loops, best of 3: 19.2 ms per loop
# list append and join
# 100 loops, best of 3: 144 ms per loop
# bytearray() +=
# 100 loops, best of 3: 3.8 ms per loop
# str() +=
# 100 loops, best of 3: 5.11 ms per loop
В Python >= 3.6, новый Ф-строки является эффективным способом, чтобы объединить строку.
>>> name = 'some_name'
>>> number = 123
>>>
>>> f'Name is {name} and the number is {number}.'
'Name is some_name and the number is 123.'
Если строки объединении являются литералы, используйте строковый литерал конкатенации
re.compile(
"[A-Za-z_]" # letter or underscore
"[A-Za-z0-9_]*" # letter, digit or underscore
)
Это полезно, если вы хотите прокомментировать часть строки (как выше) или если вы хотите использовать сырые strings или тройные кавычки для части буквальный, но не все.
Поскольку это происходит на синтаксис слоя используется нулевой операторы конкатенации.
Хотя и несколько устаревшей, код как Pythonista: идиоматические питона рекомендует присоединиться()за
+` [в этом разделе][2]. Как PythonSpeedPerformanceTips в разделе сцепление, со следующей оговоркой:
точность данного раздела является спорной по отношению к позже По версии Python. В с CPython 2.5, конкатенация строк достаточно быстрый, хотя это не может относиться также к другим питона реализаций. Увидеть ConcatenationTestCode для обсуждения.
[2]: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.building-strings-from-substrings html#
Вы пишете эту функцию
def str_join(*args):
return ''.join(map(str, args))
Затем вы можете просто позвонить туда, куда вы хотите
str_join('Pine') # Returns : Pine
str_join('Pine', 'apple') # Returns : Pineapple
str_join('Pine', 'apple', 3) # Returns : Pineapple3
Используя вместо конкатенации строк с помощью '+' - это худший способ конкатенации с точки зрения стабильности и перекрестные реализации, так как он не поддерживает все значения. Стандарту PEP8 от этого отговаривает и рекомендует использовать формат(), присоединиться() и append() для долгосрочного использования.
Как @фирмой JDI упоминает документации Python предлагает использовать ул. присоединиться " или " Ио.StringIO для конкатенации строк. И говорит, что разработчик должен ожидать квадратичное время от
+=` в цикле, хотя там'ы оптимизации начиная с версии Python 2.4. Как это ответ говорит:
если Python обнаруживает, что левый аргумент имеет нет других ссылок, он называет
realloc
, чтобы попытаться избежать копирования, изменения размера строки. Это не то, что вы должны полагаться на, Потому что это'ы деталь реализации, а потому, что еслиrealloc
заканчивается необходимость пересесть часто строку, производительность снижается в любом случае до o(п^2).
Я покажу пример реального кода, которые наивно полагались на +=
это оптимизация, но это не'т применять. Приведенный ниже код преобразует повторяемое из короткие строки в более крупные куски, чтобы быть использованы в объемном API-интерфейс.
def test_concat_chunk(seq, split_by):
result = ['']
for item in seq:
if len(result[-1]) + len(item) > split_by:
result.append('')
result[-1] += item
return result
Этот код может литературный работать в течение нескольких часов из-за квадратичной временной сложностью. Ниже представлены альтернативы с предложенной структуры данных:
import io
def test_stringio_chunk(seq, split_by):
def chunk():
buf = io.StringIO()
size = 0
for item in seq:
if size + len(item) <= split_by:
size += buf.write(item)
else:
yield buf.getvalue()
buf = io.StringIO()
size = buf.write(item)
if size:
yield buf.getvalue()
return list(chunk())
def test_join_chunk(seq, split_by):
def chunk():
buf = []
size = 0
for item in seq:
if size + len(item) <= split_by:
buf.append(item)
size += len(item)
else:
yield ''.join(buf)
buf.clear()
buf.append(item)
size = len(item)
if size:
yield ''.join(buf)
return list(chunk())
И микро-тест:
import timeit
import random
import string
import matplotlib.pyplot as plt
line = ''.join(random.choices(
string.ascii_uppercase + string.digits, k=512)) + '\n'
x = []
y_concat = []
y_stringio = []
y_join = []
n = 5
for i in range(1, 11):
x.append(i)
seq = [line] * (20 * 2 ** 20 // len(line))
chunk_size = i * 2 ** 20
y_concat.append(
timeit.timeit(lambda: test_concat_chunk(seq, chunk_size), number=n) / n)
y_stringio.append(
timeit.timeit(lambda: test_stringio_chunk(seq, chunk_size), number=n) / n)
y_join.append(
timeit.timeit(lambda: test_join_chunk(seq, chunk_size), number=n) / n)
plt.plot(x, y_concat)
plt.plot(x, y_stringio)
plt.plot(x, y_join)
plt.legend(['concat', 'stringio', 'join'], loc='upper left')
plt.show()
мой случай использования был слегка отличаться. Я должен построить запрос, в котором было более 20 полей динамически. Я за этот подход, используя метод format
query = "insert into {0}({1},{2},{3}) values({4}, {5}, {6})"
query.format('users','name','age','dna','suzan',1010,'nda')
это было для меня сравнительно проще вместо того, чтобы использовать + или другими способами
Вы можете сделать разными способами.
``питон str1 выглядит следующим образом = "Привет" стр2 = "в мире"и str_list = ['Привет', 'мир'] str_dict = {'str1 выглядит следующим образом': 'Привет', 'стр2': 'мир'}
печати(str1 выглядит следующим образом + ' ' + стр2) # Привет Мир
печать (на" ьquot%ы %ы&; % (str1 выглядит следующим образом, стр2)) # Привет Мир
Строка # форматирование с { } операторы с ул. формат() печать (на" {} {} себе".формат(str1 выглядит следующим образом, стр2)) # Привет Мир я печать (на"{0}{1}&;.формат(str1 выглядит следующим образом, стр2)) # Привет Мир я печать (на"{str1 выглядит следующим образом} {стр2}&;.формат(str1 выглядит следующим образом=str_dict['str1 выглядит следующим образом'], стр2=str_dict['стр2'])) # Привет Мир я печать (на"{str1 выглядит следующим образом} {стр2}&;.формат(**str_dict)) # Привет Мир
печать(' '.присоединиться(str_list)) # Привет Мир
печати(ф" и{str1 выглядит следующим образом} {строка str2} себе") # Привет Мир ``
Я создал это маленькое резюме по следующим статьям.
Вы можете использовать этот(более эффективный) тоже. (https://softwareengineering.stackexchange.com/questions/304445/why-is-s-better-than-for-concatenation)
s += "%s" %(stringfromelsewhere)