Как объединить строки в Python: использование .join() вместо +
Понятное — не всегда значит лучшее.
: официальный арт к игре «ведьмак 3» / cd projekt red
Python ценят за его интуитивную понятность. Так, строки можно объединить простым плюсом:
На первый взгляд странно, что многие профессиональные Python-разработчики не пользуются этим очевидным и, казалось бы, удобным методом, а вместо него применяют .join().
Почему — давайте разбираться.
Что ещё за .join() такой?
Возьмём те же строки s1 и s2 и попробуем повторить предыдущий результат с помощью .join():
Первая мысль: что здесь происходит? Зачем пустая строка? Почему строки s1 и s2 засунуты в список? Почему всё так не наглядно? А это точно Python?
Итак, по порядку:
- Пустая строка ' ' — это строка-соединитель: то, что будет между строками s1 и s2. В нашем случае она пустая, но это не обязательно — там может быть, например, пробел или знак препинания.
- Строки s1 и s2 составлены в список [s1, s2] потому, что join() принимает только один аргумент. Как правило, это итерируемый объект — список, кортеж или словарь из строк. В случае словаря функция join() объединит его ключи.
Вроде бы с join() разобрались. Но главный вопрос остался открытым: «Зачем его использовать?»
Когда строк много
Представим, что вы получили много строк в одном списке и теперь надо объединить их в одну. Попробуем решить задачу с помощью плюса:
В теле функции join_strs() мы создаём пустую строку result. Далее с помощью цикла for бежим по полученному списку из строк и с каждой итерацией добавляем к строке result пробел и строку из списка — с помощью плюса, разумеется.
В конце return возвращает строку result без первого элемента — там стоит ненужный нам пробел, добавившийся при первой итерации.
Итак, чтобы использовать ‘+’ для объединения строк из списка:
- нужен цикл for,
- нужно помнить о лишнем пробеле.
Посмотрим, что может предложить join():
Ого! Выглядит неплохо: никаких циклов и не надо беспокоиться о пробеле — функция сама обо всём позаботилась, причём в одну строчку.
В принципе, этого уже достаточно, чтобы забыть о ‘+’ — во всяком случае, для большого количества строк. Но есть ещё одна — возможно, главная — причина.
Производительность
Встроенная Python-библиотека timeit предназначена для измерения времени исполнения кода небольшого размера (скриптов, или сниппетов). Как раз наш случай.
Передадим код из примеров выше в качестве аргумента в функцию timeit.timeit(), исполним его миллион раз для обеих наших функций и сравним время:
Объединение шести строк в одну с помощью плюса в три раза медленнее, чем объединение этих же строк с помощью функции join().
С увеличением количества объединяемых строк эта разница будет расти — попробуйте проверить это самостоятельно.
В чём причина?
Как работают + и join()
Приблизительная схема работы цикла for с плюсом внутри выглядит примерно так.
- На каждой итерации цикла из списка вынимается строка.
- Интерпретатор выполняет команду result += ' ' + s, сначала запрашивая память для пробела ' '.
- Затем он запрашивает память для строки s.
- Так происходит шесть раз, и в каждой итерации есть два запроса в память — для пробела и для строки, итого 12.
А что происходит, когда мы объединяем эти же строки с помощью .join()?
- Интерпретатор подсчитывает количество строк в списке: 6.
- Подсчитывает количество нужных для объединения пробелов: 5.
- Обращается в память сразу за одиннадцатью ячейками.
- Формирует строку, выдаёт результат.
Как видим, всё происходит гораздо компактнее. Меньшее количество обращений к памяти — основная причина более высокой скорости работы функции join() по сравнению с циклом for и +.
Подытожим
Дружелюбие синтаксиса Python к начинающим — это прекрасно, без всяких преувеличений. Но если программист не хочет быть начинающим всю свою жизнь, то придётся постоянно осваивать более мощные и часто менее очевидные инструменты, подходы и приёмы.
На курсах «Профессии Python-разработчик» вы не только познакомитесь именно с такими инструментами, но и выработаете привычку к постоянному их поиску и совершенствованию. В этом, возможно, и заключается суть программирования. Приходите, и да пребудут с вами Дзен и Дух Пайтона!