Вопрос-Ответ

Which is the preferred way to concatenate a string in Python? [duplicate]

Какой предпочтительный способ объединения строки в Python?

Поскольку Python string нельзя изменить, мне было интересно, как объединить строку более эффективно?

Я могу написать подобным образом:

s += stringfromelsewhere

или как это:

s = []

s.append(somestring)

# later

s = ''.join(s)

При написании этого вопроса я нашел хорошую статью, посвященную этой теме.

http://www.skymind.com/~ocrow/python_string/

Но это в Python 2.x. , поэтому возникает вопрос, изменилось ли что-то в Python 3?

Переведено автоматически
Ответ 1

Лучший способ добавления строки к строковой переменной - использовать + или +=. Это потому, что он удобочитаем и быстр. Они также такие же быстрые, какой из них вы выберете - дело вкуса, последний является наиболее распространенным. Вот тайминги с timeit модулем:

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.join(a):
0.43739795684814453

Упс. Оказывается, даже в этом случае добавление / объединение выполняется медленнее.

Итак, откуда взялась эта рекомендация? Python 2?

a += b:
0.165287017822
a.append(b):
0.0132720470428
a.join(a):
0.114929914474

Ну, append / join там незначительно быстрее, если вы используете чрезвычайно длинные строки (чего вы обычно не делаете, какая у вас строка размером 100 МБ в памяти?)

Но настоящим решающим фактором является Python 2.3. Где я даже не буду показывать вам тайминги, потому что он настолько медленный, что еще не завершен. Эти тесты внезапно занимают минуты. За исключением добавления / объединения, которое выполняется так же быстро, как и в более поздних Pythons.

Ага. Объединение строк в Python было очень медленным еще в каменном веке. Но в версии 2.4 этого больше нет (или, по крайней мере, в версии Python 2.4.7), поэтому рекомендация использовать append / join устарела в 2008 году, когда Python 2.3 перестал обновляться, и вам следовало прекратить его использовать. :-)

(Обновление: при более тщательном тестировании выяснилось, что использование + и += также быстрее для двух строк в Python 2.3. Рекомендация использовать ''.join() должно быть, недоразумение)

Однако это CPython. У других реализаций могут быть другие проблемы. И это всего лишь еще одна причина, по которой преждевременная оптимизация является корнем всего зла. Не используйте метод, который считается "более быстрым", если вы сначала не измерите его.

Следовательно, "лучшая" версия для выполнения конкатенации строк - использовать + или +=. И если это окажется для вас медленным, что довольно маловероятно, тогда сделайте что-нибудь еще.

Итак, почему я использую много методов добавления / объединения в своем коде? Потому что иногда это на самом деле понятнее. Особенно когда все, что вы должны объединить вместе, должно быть разделено пробелами, запятыми или переводом строки.

Ответ 2

Если вы объединяете много значений, то ни то, ни другое. Добавление списка обходится дорого. Для этого можно использовать StringIO . Особенно если вы создаете его с помощью множества операций.

from cStringIO import StringIO
# python3: from io import StringIO

buf = StringIO()

buf.write('foo')
buf.write('foo')
buf.write('foo')

buf.getvalue()
# 'foofoofoo'

Если у вас уже есть полный список, возвращенный вам в результате какой-либо другой операции, то просто используйте ''.join(aList)

Из часто задаваемых вопросов по Python: Какой наиболее эффективный способ объединения множества строк вместе?


объекты str и bytes неизменяемы, поэтому объединение многих строк вместе неэффективно, поскольку каждое объединение создает новый объект. В общем случае общая стоимость выполнения пропорциональна общей длине строки.


Чтобы накопить много объектов str, рекомендуемая идиома - поместить их в список и вызвать str.join() в конце:


chunks = []
for s in my_strings:
chunks.append(s)
result = ''.join(chunks)

(еще одна достаточно эффективная идиома - использовать io.StringIO)


Для накопления объектов с большим количеством байтов рекомендуемая идиома - расширить объект bytearray с помощью конкатенации на месте (оператор +=):


result = bytearray()
for b in my_bytes_objects:
result += b


Редактировать: я был глуп и вставил результаты в обратном порядке, чтобы это выглядело так, будто добавление в список было быстрее, чем cStringIO. Я также добавил тесты для объединения bytearray / str, а также второй раунд тестов с использованием большего списка с более крупными строками. (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
Ответ 3

В Python >= 3.6 новый f-string является эффективным способом объединения строки.

>>> name = 'some_name'
>>> number = 123
>>>
>>> f'Name is {name} and the number is {number}.'
'Name is some_name and the number is 123.'
Ответ 4

Использование вместо объединения строк символа '+' является НАИХУДШИМ методом объединения с точки зрения стабильности и перекрестной реализации, поскольку он не поддерживает все значения. Стандарт PEP8 не поощряет это и поощряет использование format(), join() и append() для долгосрочного использования.

Цитируется из связанного раздела "Рекомендации по программированию":


Например, не полагайтесь на эффективную реализацию CPython объединения строк на месте для операторов в форме a + = b или a = a + b. Эта оптимизация хрупка даже в CPython (она работает только для некоторых типов) и вообще отсутствует в реализациях, которые не используют пересчет. В частях библиотеки, чувствительных к производительности, вместо этого следует использовать форму ".join() . Это гарантирует, что объединение происходит за линейное время в различных реализациях.


python python-3.x string