Распространенным антипаттерном в Python является объединение последовательности строк +
в цикле. Это плохо, потому что интерпретатор Python должен создавать новый строковый объект для каждой итерации, а это в конечном итоге занимает квадратичное время. (Последние версии CPython, очевидно, могут оптимизировать это в некоторых случаях, но другие реализации не могут, поэтому программисты не рекомендуется полагаться на это.) ''.join
- правильный способ сделать это.
Тем не менее, я слышал (в том числе здесь, в Stack Overflow ), что вы никогда не должны использовать +
для конкатенации строк, а вместо этого всегда используйте ''.join
или строку формата. Я не понимаю, почему это так, если вы объединяете только две строки. Если я правильно понимаю, это не должно занимать квадратичное время, и я думаю, что a + b
он чище и читабельнее, чем любой ''.join((a, b))
или '%s%s' % (a, b)
.
Является ли хорошей практикой +
объединение двух строк? Или есть проблема, о которой я не знаю?
+
быстрее или медленнее? И почему?In [2]: %timeit "a"*80 + "b"*80
1000000 loops, best of 3: 356 ns per loop
In [3]: %timeit "%s%s" % ("a"*80, "b"*80)
1000000 loops, best of 3: 907 ns per loop
In [3]: %timeit "%s%s" % (a, b) 1000000 loops, best of 3: 590 ns per loop
In [4]: %timeit a + b 10000000 loops, best of 3: 147 ns per loop
__str__
. См. Мой ответ для примеров.Ответы:
Нет ничего плохого в том, чтобы объединить две строки с помощью
+
. На самом деле это легче читать, чем''.join([a, b])
.Вы правы, хотя объединение более двух строк с помощью
+
является операцией O (n ^ 2) (по сравнению с O (n) дляjoin
) и, таким образом, становится неэффективным. Однако это не связано с использованием цикла. Дажеa + b + c + ...
O (n ^ 2), причина в том, что каждая конкатенация создает новую строку.CPython2.4 и выше пытаются смягчить это, но все же рекомендуется использовать
join
при объединении более двух строк.источник
.join
принимает итерацию, поэтому допустимы оба.join([a,b])
и.join((a,b))
.+
или+=
в принятом ответе (с 2013 года) на stackoverflow.com/a/12171382/378826 (от Леннарта Регебро) даже для CPython 2.3+ и выбирать шаблон «добавление / присоединение» только в том случае, если этот более ясный Идея решения поставленной проблемы.Оператор Plus - прекрасное решение для объединения двух строк Python. Но если вы продолжите добавлять более двух строк (n> 25), вы можете подумать о другом.
''.join([a, b, c])
Уловка - это оптимизация производительности.источник
append()
добавление строк в список.n > 25
. Людям нужны ориентиры, чтобы с чего-то начать.Предположение, что никогда не следует использовать + для конкатенации строк, а вместо этого всегда использовать '.join, может быть мифом. Это правда, что использование
+
создает ненужные временные копии неизменяемого строкового объекта, но другой не часто цитируемый факт заключается в том, что вызовjoin
в цикле обычно увеличивает накладные расходыfunction call
. Возьмем ваш пример.Создайте два списка, один из связанного вопроса SO, а другой - более крупный сфабрикованный
Позволяет создать две функции,
UseJoin
иUsePlus
использовать соответствующиеjoin
и+
функциональность.Давайте запустим timeit с первым списком
У них почти одинаковая продолжительность работы.
Давайте использовать cProfile
И похоже, что использование Join приводит к ненужным вызовам функций, которые могут увеличить накладные расходы.
Теперь вернемся к вопросу. Следует ли препятствовать использованию
+
сверхjoin
во всех случаях ?Я считаю, что нет, все следует принимать во внимание
И, конечно же, в разработке преждевременная оптимизация - зло.
источник
join
внутри самого цикла - скорее, цикл генерировал бы последовательность, которая будет передана для соединения.При работе с несколькими людьми иногда сложно точно знать, что происходит. Использование строки формата вместо конкатенации может избежать одной неприятности, которая случилась с нами много раз:
Скажем, функции требуется аргумент, и вы пишете его, ожидая получить строку:
Так что эту функцию можно довольно часто использовать во всем коде. Ваши коллеги могут точно знать, что он делает, но не обязательно полностью осведомлены о внутреннем устройстве и могут не знать, что функция ожидает строку. И в итоге они могут получить вот что:
Не было бы проблем, если бы вы просто использовали строку формата:
То же самое верно для всех типов определяющих объектов
__str__
, которые также могут быть переданы:Итак, да: если вы можете использовать строку формата, сделайте это и воспользуйтесь тем, что может предложить Python.
источник
+
.zeta = u"a\xac\u1234\u20ac\U00008000"
вам придется использовать,print 'bar: ' + unicode(zeta)
чтобы убедиться, что это не ошибка.%s
делает это правильно, не задумываясь, и намного короче"bar: %s"
могут быть переведены на"zrb: %s br"
другой язык.%s
Версия будет только работать, но версия строки-CONCAT станет беспорядком обрабатывать все дела и ваши переводчики теперь будут иметь два отдельных переводов для решенияdef
.Я сделал быстрый тест:
и рассчитал это:
Видимо есть оптимизация под
a = a + b
случай. Он не показывает время O (n ^ 2), как можно было бы предположить.Так что, по крайней мере, с точки зрения производительности, использование
+
- это нормально.источник
Согласно документам Python, использование str.join () обеспечит стабильность производительности в различных реализациях Python. Хотя CPython оптимизирует квадратичное поведение s = s + t, другие реализации Python могут этого не делать.
Типы последовательностей в документации Python (см. Сноску [6])
источник
Я использую следующее с python 3.8
источник
'' .join ([a, b]) - лучшее решение, чем + .
Поскольку код должен быть написан таким образом, чтобы не ставить в невыгодное положение другие реализации Python (PyPy, Jython, IronPython, Cython, Psyco и т. Д.)
форма a + = b или a = a + b является хрупкой даже в CPython и вообще не присутствует в реализациях, которые не используют подсчет ссылок (подсчет ссылок - это метод хранения количества ссылок, указателей или дескрипторов для ресурс, такой как объект, блок памяти, дисковое пространство или другой ресурс )
https://www.python.org/dev/peps/pep-0008/#programming-recommendations
источник
a += b
работает во всех реализациях Python, просто в некоторых из них требуется квадратичное время, когда выполняется внутри цикла ; вопрос касался конкатенации строк вне цикла.