Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 18 из 20 Начальный 15 мин 100 XP

Строки и списки: перевод туда-обратно

Строка ведёт себя почти как список символов, но с одним запретом — на изменение. Учимся свободно переводить строку в список и обратно и использовать силу обоих миров.

Редакция Питоники

В уроке 1 мы выяснили: строку нельзя изменить по индексу. Но у списков такого запрета нет — они изменяемые свободно. Отсюда практичный приём: нужно «изменить» строку — превратите её в список, сделайте правки, соберите обратно через join. Разбираем мост между двумя типами по кусочкам.

list: строка становится списком

list(строка) разбирает текст на отдельные символы. Получившийся список — обычный: его можно менять, добавлять в него элементы, считать len. Перебор строки циклом for работает и без list — прямо по символам.

разбор и перебор
letters = list('каток')
print(letters)

for ch in 'окт':
    print(ch)
Вывод
['к', 'а', 'т', 'о', 'к']
о
к
т

join: сборка обратно

''.join(список) склеивает символы без разделителя — строка собрана. С разделителем — вставляет его между элементами: ', '.join делает читаемый перечень. Пустой разделитель и join с запятой — два самых частых вызова метода.

сборка из списка
letters = ['к', 'о', 'т']
print(''.join(letters))
print(', '.join(['Анна', 'Олег', 'Ира']))
Вывод
кот
Анна, Олег, Ира

Замена символа через список

Теперь обход неизменяемости из урока 1 в полный рост: превращаем строку в список, меняем символ по индексу (списку это можно), собираем обратно. Три строки — и «изменённая» строка готова.

меняем символ через список
word = 'кот'
chars = list(word)
chars[0] = 'р'
print(''.join(chars))
Вывод
рот

sorted: буквы по порядку

sorted(строка) сортирует символы и возвращает СПИСОК (не строку!) — классическая ловушка. Строкой результат делает join. Побочный эффект сортировки — проверка анаграмм: два слова анаграммы, если их отсортированные буквы равны.

сортировка букв и анаграммы
print(sorted('кот'))

print(''.join(sorted('кот')))
print(''.join(sorted('ток')))

print(sorted('кот') == sorted('ток'))
Вывод
['к', 'о', 'т']
кот
кот
True
ОперацияКодРезультат
Строка → списокlist('кот')['к', 'о', 'т']
Список → строка''.join(['к', 'о', 'т'])'кот'
Сортировкаsorted('кот')['к', 'о', 'т'] (список!)
Правка символаchars[0] = 'р' + joinновая строка 'рот'

Строка и список — две проекции одной последовательности: строка неизменяема и оптимизирована под текст, список изменяем и оптимизирован под правки. Мост list/join стоит запомнить как единый приём.

Как превратить строку в список символов

Строка ведёт себя почти как список символов, но с одним запретом — на изменение. Всё остальное у неё есть: индексы, срезы, len, in, обход циклом. У списков такого запрета нет, они изменяемые свободно. Отсюда практичный приём: нужно «изменить» строку — превратите её в список, сделайте правки, соберите обратно.

разбор и перебор
letters = list('каток')
print(letters)

for ch in 'окт':
    print(ch)
Вывод
['к', 'а', 'т', 'о', 'к']
о
к
т

Обратите внимание: list('каток') даёт пять элементов, а не один. Перебор циклом по строке работает и без list — прямо по символам. Так что если вам нужно просто пройтись по символам, конвертация не требуется: она нужна только ради изменения.

join: сборка обратно

Обратная операция — join. Разделитель вызывается у строки, список передаётся аргументом: ''.join(chars) склеивает символы без зазоров, а ', '.join(items) делает читаемый перечень. Пустой разделитель и join с запятой — два самых частых вызова метода, о которых мы подробно говорили в уроке 10.

сборка из списка
letters = ['к', 'о', 'т']
print(''.join(letters))
print(', '.join(['Анна', 'Олег', 'Ира']))
Вывод
кот
Анна, Олег, Ира

Замена символа через список

Теперь обход неизменяемости из урока 1 в полный рост: превращаем строку в список, меняем символ по индексу — списку это можно, — собираем обратно. Три строки, и «изменённая» строка готова.

меняем символ через список
word = 'кот'
chars = list(word)
chars[0] = 'р'
print(''.join(chars))
Вывод
рот

Сравните с приёмом через срез: s[:0] + 'р' + s[1:] — тоже работает, но выглядит как заклинание. Через список читается понятнее: «сделай список, поменяй первый, собери обратно». Для одной замены правда привычнее replace или срез, а вот когда правок много и они в разных местах — выигрывает список.

sorted: буквы по порядку

sorted(строка) сортирует символы и возвращает СПИСОК, а не строку. Это классическая ловушка: забытый join поверх sorted — и вместо слова печатается список букв. Побочный эффект сортировки — проверка анаграмм: два слова анаграммы, если их отсортированные буквы равны.

сортировка букв и анаграммы
print(sorted('кот'))

print(''.join(sorted('кот')))
print(''.join(sorted('ток')))

print(sorted('кот') == sorted('ток'))
Вывод
['к', 'о', 'т']
кот
кот
True

Проверка анаграмм через sorted работает и для слов целиком: 'listen'.lower() == 'silent'.lower() даст True после сортировки букв. Но обратите внимание: sorted вернул список, а сравнили мы списки — это честно, списки сравниваются поэлементно. Строка после join тоже сравнилась бы, но список сравнивается быстрее: он хранит ссылки на уже существующие объекты, а не пересоздаёт символы.

ЗадачаКак написатьЧто получится
Строка → список символовlist('кот')['к', 'о', 'т']
Список → строка''.join(chars)'кот'
Перебор символовfor ch in s:по одному символу
Замена символаchars[0] = 'р'; ''.join(chars)'рот'
Сортировка буквsorted('кот')список, не строка
Проверка анаграммsorted(a) == sorted(b)True / False

Ещё один мост между мирами — enumerate. Он даёт и позицию, и символ: for i, ch in enumerate(s). Когда нужно править символы по индексам и знать, где именно вы находитесь, это ровно то, что нужно. Альтернатива range(len(s)) работает, но enumerate считается идиоматичнее — и это тот случай, когда разница не в скорости, а в читаемости кода.

И последнее. list() принимает не только строки — это общий механизм превращения любой итерируемой последовательности в список. list(range(5)) даёт [0, 1, 2, 3, 4], list(generator) — список из того, что выдаст генератор. Со строками работает то же правило, и это ещё одна причина не путать list(s) с s.split(): первое разбивает на символы, второе — по разделителю.

Строки и списки: как выбрать правильный тип

Строки и списки выглядят похоже: оба поддерживают индексы, срезы, len, in и обход циклом. Разница одна, но она определяет всё: строка неизменяема, список — нет. Отсюда вытекает простое правило выбора.

Что нужноТип данныхПочему
Данные пришли текстомстроканечего менять, всё уже в одном объекте
Нужно отсортировать на местесписоку строк sort не работает вовсе
Нужно удалить элементсписоку строк нет remove и pop
Нужно положить значение в ключстрокастроки неизменяемы и безопасны как ключи
Нужно сравнивать как «один объект»строканеизменяемость даёт быстрое сравнение
Нужно собрать результат из частейсписок + joinjoin склеит всё за один проход

Отдельная строка про скорость сравнения. Строки Python при сравнении == сначала проверяют, совпадают ли объекты, и только потом сравнивают содержимое. Для неизменяемых строк это безопасно, и потому сравнение двух строк часто оказывается быстрее, чем сравнение двух списков. Но на коротких текстах разница не измерима — она становится заметной на больших объёмах и в горячих циклах.

И последнее, что связывает урок с остальным курсом. Неизменяемость строк — не ограничение, а защита. Когда вы передаёте строку в функцию, она не может измениться «по дороге», и две части программы не могут испортить данные друг другу. Списки такой гарантии не дают, и в коде с ними приходится быть внимательнее к копированию.

Практика: разбор строки в словарь

Соберём вместе всё, что урок дал: строку разбираем, чистим, ключи приводим к единому регистру и складываем в словарь. Это не учебный пример — такой разбор встречается в каждом разборе конфигурации, заголовка HTTP или строки параметров.

пары ключ-значение в словарь
raw = 'Name=anna;City=Kazan;Age=30'
pairs = raw.split(';')
data = {}
for pair in pairs:
    key, value = pair.split('=')
    data[key.lower()] = value.strip()
print(data)
print(data['city'])
Вывод
{'name': 'anna', 'city': 'Kazan', 'age': '30'}
Kazan

Обратите внимание на две нормализации. Ключ приводится к нижнему регистру — чтобы искать по нему можно было не думая о написании. Значение только чистится: «Kazan» и «kazan» — это, возможно, разные города, и решать должен бизнес, а не код. Второй момент: разделитель ; выбран не случайно — = в значениях встречается чаще, и если бы он был разделителем, строку пришлось бы резать аккуратнее.

И напоследок. Весь урок свёлся к одной мысли: строка — это значение, и чтобы из неё получить данные, её надо разобрать. split даёт части, strip чистит их, lower приводит к единому виду, join собирает обратно. Эти четыре метода закрывают почти все задачи разбора текста, с которыми сталкивается Python-разработчик.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

chars = list('мир')
chars.reverse()
print(''.join(chars))
print(', '.join(['а', 'б']))
chars = list('кот')
chars[0] = 'р'
print(''.join(chars))
Проверь себя
0 / 8

1. Что вернёт list('ок')?

2. Как собрать из ['к', 'о', 'т'] строку 'кот'?

3. Что вернёт sorted('кот')?

4. Как проверить, что слова «кот» и «ток» — анаграммы?

5. Зачем переводить строку в список, если она и так последовательность?

6. Что вернёт list('ок')?

7. Как заменить первый символ строки на 'р'?

8. Что вернёт ''.join(list('кот'))?

Карточки терминов
Запомнено: 0 / 6
Практика

Из слова 'свет' получите слово 'цвет': превратите строку в список, замените первый символ (индекс 0) на 'ц', соберите через join и напечатайте. Затем напечатайте буквы 'свет' по порядку алфавита одной строкой.

practice.py
Вопросы и ответы по уроку

Что быстрее: replace или замена через список?

Для замены всех вхождений — replace: он написан на C и работает за один проход. Список выигрывает, когда правки разнородные и по индексам: одна конвертация вместо цепочки replace и срезов.

Как перебрать строку с индексами?

enumerate(s) — цикл for i, ch in enumerate(s) даёт и позицию, и символ. Или range(len(s)) — но enumerate считается идиоматичнее.

Что быстрее: replace или замена через список?

Для замены всех вхождений — replace: он написан на C и работает за один проход. Список выигрывает, когда правки разнородные и по индексам: одна конвертация вместо цепочки replace и срезов. Для одной замены проще срез или replace.

Почему sorted возвращает список, а не строку?

sorted — универсальная функция: она сортирует любой перебираемый объект и всегда возвращает список. Это единообразие ценнее удобства; для строк поверх добавьте ''.join.

Как перебрать строку с индексами?

Функцией enumerate: цикл for i, ch in enumerate(s) даёт и позицию, и символ. Или range(len(s)) — но enumerate считается идиоматичнее, и при разнице в скорости код читается понятнее.

Как проверить, что два слова — анаграммы?

Отсортировать буквы и сравнить: sorted('кот') == sorted('ток') даёт True. Для слов целиком не забудьте привести к одному регистру: sorted(a.lower()) == sorted(b.lower()).

Понравился урок? Сошлитесь на него

«В уроке 1 мы выяснили: строку нельзя изменить по индексу.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.