EduBrick
классная работа

Методы строк

Программирование на Python: от нуля до олимпиад

0/18решено 0 из 18до зачёта осталось 10

Чему научитесь

  • Пользоваться готовыми методами вместо самодельных циклов
  • Понимать, почему метод не меняет строку, а возвращает новую
  • Разбивать текст на слова и собирать обратно
  • Отличать случаи, где метод есть, от тех, где нужен цикл

Как устроено занятие

Сначала разбор с примерами и короткими проверками понимания — они нужны, чтобы поймать непонятое сразу, а не через три темы.

Дальше 15 задач лестницей: разминка, основа, со звёздочкой. Занятие засчитывается, когда решено 10 — остальные не пропадают и учитываются отдельно.

После занятия — вторая часть, ещё 15 задач на те же приёмы в новых сюжетах.

Сколько это займёт

Примерно час-полтора вместе с задачами. Сроков нет: можно закрыть вкладку и вернуться когда удобно — прогресс сохранится.

теория

Действия, которые строка умеет сама

В прошлом занятии всё делалось вручную: посчитать символы — цикл, найти позицию — цикл, убрать символ — снова цикл. Это было полезно: теперь понятно, что происходит внутри.

А внутри Python это уже написано. У строки есть методы — действия, которые она выполняет над собой:

s = "Hello World"

print(s.lower())        # hello world
print(s.upper())        # HELLO WORLD
print(s.count("l"))     # 3
print(s.find("World"))  # 6 — номер, с которого начинается

Записывается через точку: сначала строка, потом имя метода, потом скобки. В скобках — то, что методу нужно знать.

метод что делает
s.lower(), s.upper() новая строка в нужном регистре
s.count(x) сколько раз встречается x
s.find(x) номер первого вхождения или −1
s.replace(a, b) новая строка, где все a заменены на b
s.strip() новая строка без пробелов по краям

Обратите внимание на слово «новая» — оно ключевое, и следующий блок весь про него.

теория

Строку нельзя изменить

Это главное, что нужно понять про строки в Python, и главный источник ошибок.

Строка неизменяема. Однажды созданная, она остаётся такой навсегда. Ни один метод её не меняет — каждый возвращает новую строку.

s = "hello"
s.upper()          # новая строка создана… и потеряна
print(s)           # hello — s не изменился

Программа не падает, не ругается, просто ничего не делает. Ошибку такого рода ищут долго именно потому, что код выглядит правильным.

Чтобы результат сохранился, его надо куда-то положить:

s = s.upper()      # теперь s — новая строка
print(s)           # HELLO

Или сразу использовать: print(s.upper()).

По той же причине не работает s[0] = "x" — изменить символ на месте нельзя. Нужна новая строка: через replace, через сборку в цикле или через методы, которые вы узнаете дальше.

Зато методы легко ставятся в цепочку — каждый получает результат предыдущего:

print(s.lower().strip().replace(" ", "-"))
тест

Проверка: что напечатается

s = "abc"
s.replace("a", "z")
print(s)

Что выведет программа?

Войдите, чтобы ответить.
теория

split и join: разобрать и собрать

Два метода, ради которых стоит выучить остальные. split разбивает строку на слова:

s = "  one   two three "
parts = s.split()        # ["one", "two", "three"]

print(len(parts))        # 3 — сколько слов
for word in parts:
    print(word)

Без аргументов split сам разбирается с несколькими пробелами подряд и с пробелами по краям — вручную это писать заметно дольше.

То, что он возвращает, называется списком. Подробно списки — следующий модуль, а пока достаточно двух свойств: список можно перебрать циклом for и узнать его длину через len.

join делает обратное — собирает слова в строку. Вызывается он у разделителя, и это выглядит непривычно:

print("-".join(parts))     # one-two-three
print(" ".join(parts))     # one two three
print("".join(parts))      # onetwothree

Читается как «склей это через дефис». Пара split + join решает половину задач на текст: разобрал, что-то сделал, собрал обратно.

теория

Проверки: isdigit, isalpha и другие

Вместо сравнения с границами алфавита есть готовые проверки. Они отвечают True или False:

проверка истинна, когда
s.isdigit() все символы — цифры
s.isalpha() все символы — буквы
s.isupper(), s.islower() все буквы нужного регистра
s.startswith(x), s.endswith(x) строка начинается или кончается на x

Работают они и на целой строке, и на отдельном символе — символ ведь тоже строка, просто из одного знака:

for ch in s:
    if ch.isdigit():
        total += int(ch)

Две ловушки

"-12".isdigit() — это False. Минус не цифра, и точка тоже: "12.5".isdigit() даёт False. Проверка отвечает буквально на вопрос «все ли символы цифры», а не «похоже ли это на число».

И вторая: пробел не буква. У строки "a b" метод isalpha() вернёт False, хотя букв там две.

тест

Проверка: что вернёт isdigit

Для каких из этих строк isdigit() вернёт True?

Войдите, чтобы ответить.
теория

Когда метод, а когда цикл

Метод короче и работает быстрее написанного вручную цикла. Но подходит он не всегда.

задача чем решать
посчитать вхождения символа или куска count
найти позицию find
заменить одно на другое replace
разбить на слова, собрать обратно split, join
проверить состав строки isdigit, isalpha
условие сложнее, чем «равно» цикл
нужно сравнивать соседние символы цикл
нужно что-то накопить по ходу цикл

Правило простое: есть готовый метод — берите метод. Написанный вручную аналог count не станет ни понятнее, ни быстрее.

Но как только условие перестаёт быть простым сравнением — «символ, у которого сосед слева гласный», — метода не найдётся, и работает обычный цикл из прошлого занятия. Одно не отменяет другого.

Часто удобна смесь: разбить строку методом, а дальше перебрать циклом. Так решается почти всё в сегодняшней практике.

теория

Три ошибки этого занятия

Результат метода потерян. s.replace("a", "b") без присваивания. Признак: программа выводит исходную строку и выглядит при этом безупречно. Проверяйте: у каждого вызова метода результат либо присвоен, либо сразу напечатан.

Путаница между find и «нашлось». find возвращает −1, когда не нашёл, а не 0. И нумерация у него с нуля. Если в условии позиции считаются с единицы, преобразование делается один раз и аккуратно.

isdigit принят за «это число». Для -12 и 12.5 он даёт False. Если в задаче встречаются отрицательные числа или дроби, эта проверка не годится.

Как проверять себя

  • строка из одних пробеловsplit() даст пустой список, и цикл по нему не выполнится ни разу;
  • искомого нет вовсе — что вернут find и count, и что должна вывести программа;
  • строка из одного слова — не рассчитывает ли решение хотя бы на два.
теория

Практика: пятнадцать задач

Лестница прежняя: пять разминочных, семь основных, три со звёздочкой. Зачёт при десяти решённых.

Почти каждую задачу можно решить и вручную, как в прошлом занятии, и методом. Решайте методом — в этом смысл занятия. Ручной способ вы уже показали.

Срезов здесь не будет: они следующее занятие. Поэтому там, где хочется «взять кусок строки», пока обходимся split, replace и перебором.

лестница задач
развёрнутый ответ

Методы вызваны, а строка прежняя

Задача: «дана строка; выведите её строчными буквами, без пробелов по краям и с заменой всех дефисов на пробелы».

Ученик написал:

s = input()

s.lower()
s.strip()
s.replace("-", " ")

print(s)

Программа выводит строку в точности такой, какой её ввели. Объясните, почему так происходит, и приведите два способа исправить — с промежуточной переменной и без неё.

Войдите, чтобы ответить.