Генерация строк в циклах — задача, часто возникающая на практике. Типичный пример — функция, помогающая генерировать HTML-списки. Она принимает на вход коллекцию элементов и возвращает HTML-список из них:
coll = ['milk', 'butter']
build_HTML_list(coll)
# <ul><li>milk</li><li>butter</li></ul>
Как можно решить эту задачу в лоб:
- Создать переменную
result
и записать в нее<ul>
. - Пройтись циклом по элементам коллекции и дописать в результирующую строку очередной элемент
<li>
. - Добавить в конце
</ul>
и вернутьresult
из функции.
def build_HTML_list(coll):
result = '<ul>'
for item in coll:
result = f'{result}<li>{item}</li>'
# либо так: result += '<li>{item}</li>'
result = f'{result}</ul>'
return result
coll = ['milk', 'butter']
print(build_HTML_list(coll))
# => <ul><li>milk</li><li>butter</li></ul>
Такой способ вполне рабочий, но для большинства языков программирования максимально неэффективный. Дело в том, что конкатенация и интерполяция порождают новую строчку вместо старой. Подобная ситуация повторяется на каждой итерации. Причем строка становится все больше и больше. Копирование строк приводит к серьезному расходу памяти и может влиять на производительность. Конечно, для большинства приложений данная проблема неактуальна из-за малого объема прогоняемых данных, но более эффективный подход не сложнее в реализации и обладает рядом плюсов. Поэтому стоит сразу приучить себя работать правильно.
Правильно, в случае с динамическими языками – формировать список, который затем с помощью метода join()
можно превратить в строку:
def build_HTML_list(coll):
parts = []
for item in coll:
parts.append(f'<li>{item}</li>')
# Метод join объединяет элементы списка в строку
# В качестве разделителя между значениями
# используется значение строки
inner_value = ''.join(parts)
result = f'<ul>{inner_value}</ul>'
return result
Размер кода практически не изменился, но способ формирования результата стал другим. Вместо строки, сначала собирается список, который затем превращается в строку с помощью метода .join()
. У такого подхода есть и дополнительные плюсы:
- Такой код проще отлаживать. Данные, представленные списком, легче вычленять визуально и программно.
- Список — это структура, с ним можно производить дополнительные манипуляции. С готовой строкой уже ничего особо не сделать.
Регулируя разделитель, строки можно объединять разными способами. Например, через запятую с пробелом:
parts = ['python', 'PHP', 'Python']
output = ', '.join(parts)
print(output) # => python, PHP, Python
Если каждое слово надо вывести на новой строчке, то в качестве разделителя используем символ перевода строки '\n'
:
parts = ['python', 'PHP', 'Python']
# Теперь каждое слово будет начинаться с новой строки
output = '\n'.join(parts)
print(output)
# => python
# => PHP
# => Python
Последний пример особенно важен. Новички часто допускают ошибку и добавляют перевод строки в момент формирования списка, а не в join()
. Посмотрите на пример с нашей функцией build_HTML_list()
.
Правильно:
def build_HTML_list(coll):
parts = []
for item in coll:
parts.append(f'<li>{item}</li>')
inner_value = '\n'.join(parts) # перевод строки
result = f'<ul>{inner_value}</ul>'
return result
coll = ['milk', 'butter']
build_HTML_list(coll)
print # => <ul><li>milk</li>
print # => <li>butter</li></ul>
Неправильно:
def build_HTML_list(coll):
parts = []
for item in coll:
parts.append(f'\n<li>{item}</li>')
inner_value = ''.join(parts) # разделителя нет
result = f'<ul>{inner_value}</ul>'
return result
coll = ['milk', 'butter']
build_HTML_list(coll)
print # => <ul>
print # => <li>milk</li>
print # => <li>butter</li></ul>
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.