Строки и форматирование

Вывод на экран

Вы уже умеете выводить на экран текст, складывая строки. А вот как напечатать без этого? Нужно в скобках функции print() перечислить через запятую аргументы, которые она печатает:

weather = 'облачно'
print('На улице сейчас', weather)       # На улице сейчас облачно
1
2

Запятая между аргументами по умолчанию заменяется на пробел.

print('За', 'окном', 'метель')      # За окном метель
1

Это значит, что в сообщения можно не добавлять пробелы, когда составляете сложную фразу. Достаточно разделить аргументы функции print() запятой. И, что приятно, количество этих аргументов не ограничено:

messages_count = 12
print('У тебя', messages_count, 'новых сообщений.')     # У тебя 12 новых сообщений.
1
2

Упражнения

  1. Продолжим учить Виту вести беседы о погоде. Напечатайте на экран данные из списка weather_today в формате 'Сегодня гроза и на градуснике 21'. Вместо сложения строк и приведения чисел к строкам просто перечислите аргументы в скобках функции print().
weather_today = [[19, 'дождь'], [22, 'облачно'], [24, 'солнечно']]

for weather in weather_today:
    print(...)      # измените код
1
2
3
4

Метод split()

Разбить фразу на слова, и вообще разделить строку по определённому символу можно методом split() (англ. «разделить»). В результате получится список строк. Метод split() принимает аргумент, указывающий, какой разделитель использовать.

blok_string = 'Ночь. Улица. Фонарь. Аптека'
# из строки получаем список, где строку делят по сочетанию точки и пробела:
blok_list = blok_string.split('. ')
print(blok_list)            # ['Ночь', 'Улица', 'Фонарь', 'Аптека']
# можно заказать, к примеру, последнее слово:
print(blok_list[-1])        # Аптека
1
2
3
4
5
6

Замечание. Да, Python позволяет использовать отрицательные индексы для обращения к элементам списка. При этом -1 соответствует последнему элементу, -2 — предпоследнему, и т.д. В общем случае, blok_list[-k] — это то же самое, что blok_list[len(blok_list) - k], только короче. Например, если нужен пятый символ с конца списка s, можно написать s[len(s) - 5] или, короче, s[-5]. Если в вызове split() не указывать разделитель, то строка разобьётся по пробелам:

blok_string = 'Ночь. Улица.  Фонарь. Аптека.'
# из строки получаем список:
blok_list = blok_string.split()
print(blok_list)        # ['Ночь.', 'Улица.', 'Фонарь.', 'Аптека.']
1
2
3
4

Тогда появятся лишние точки на концах слов. Их удобнее всего убирать методом strip() — он убирает указанные символы в начале и в конце.

# хотим "Ночь" без точки
print(blok_list[0].strip('.'))      # Ночь
1
2

Упражнения

  1. Имеется список запросов queries. Необходимо определить, какие из них адресованы Вите, а какие — другим людям. Напишите функцию check_query(), которая принимает запрос как параметр, анализирует его и возвращает один из двух вердиктов:
  • строку 'запрос к Вите', если запрос начинается с обращения к Вите,
  • строку 'запрос к кому-то ещё', если нет.

Код вывода результатов на экран уже написан в основном теле программы.

def check_query(query):
    # напишите код тела функции
    ...

# дальше следует код, вызывающий вашу функцию; не изменяйте его:
queries = [
    'Вита, сколько у меня друзей?',
    'Андрей, ну где ты был?',
    'Андрей, ну обними меня скорей!',
    'Вита, кто все мои друзья?'
]

for q in queries:
    result = check_query(q)
    print(q, '-', result)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  1. Вы умеете звать Виту. Теперь надо научить её распознавать суть запроса. Отделите обращения — перепишите функцию check_query() так, чтобы она возвращала: Например, для запроса 'Вита, сколько у меня друзей?' верните строку 'сколько у меня друзей?'. Для запроса 'Серёга, ты где?' — строку 'ты где?'. У строки, которую она возвращает, не должно быть пробелов в начале и конце.
def check_query(query):
    # напишите код тела функции
    ...

# дальше следует код, вызывающий вашу функцию; не изменяйте его:
queries = [
    'Вита, сколько у меня друзей?',
    'Андрей, ну где ты был?',
    'Андрей, ну обними меня скорей!',
    'Вита, кто все мои друзья?'
]

for q in queries:
    result = check_query(q)
    print(q, '-', result)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Форматирование строк

До сих пор для вывода текста на экран вам приходилось собирать его из нескольких частей. Но есть и другой способ. Для сборки текста из разных элементов удобны f-строки (от англ. formatted string, «форматированные строки»). Эти f-строки включают имена переменных внутри фигурных скобок. Значения переменных подставляются в строку автоматически. В коде f-строки выглядят как обычные, только начинаются с символа f перед кавычками:

weather = 'облачно'
print(f'На улице сейчас {weather}.')

# Сравните с
# print('На улице сейчас ' + weather + '.')
# или
# print('На улице сейчас', weather, '.') — в таком коде не убрать пробел перед точкой
1
2
3
4
5
6
7

Результат вывода:

На улице сейчас облачно.
1

Преобразование типов из числа в строку f-строки проделывают автоматически:

one_hundred = 100
rubles = 'рублей'
friends = 'друзей'
print(f'Не имей {one_hundred} {rubles}, а имей {one_hundred} {friends}.')

# Это проще и понятнее, чем написать
# print('Не имей ' + str(one_hundred) + ' ' + rubles + ', а имей ' + str(one_hundred) +' ' + friends + '.')
1
2
3
4
5
6
7

Результат вывода:

Не имей 100 рублей, а имей 100 друзей.
1

Упражнения

  1. Замените объединение строк на f-строку.
def show_meteo(temperature, weather):
    print('Сейчас ' + weather + ', на градуснике ' + str(temperature) + '.')

show_meteo(24, 'облачно')
1
2
3
4
  1. В коде финальной задачи из темы «Циклы и ветвления» замените все объединения строк на f-строки.
def format_text(messages_count):
    remainder = messages_count % 10
    if messages_count == 0:
        return 'нет новых сообщений'
    elif remainder == 0 or remainder >= 5 or (10 <= messages_count <= 19):
        return messages_count + 'новых сообщений'
    elif remainder == 1:
        return messages_count + 'новое сообщение'
    else:
        return messages_count + 'новых сообщения'

def print_count(messages_count):
    text = format_text(messages_count)
    print('У вас', text, '.')

print_count(0)
print_count(1)
print_count(4)
print_count(5)
print_count(12)
print_count(22)
print_count(25)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Подробнее о форматировании

В f-строки можно подставлять не только переменные, но и результаты вычислений. Например, арифметические операции:

one_hundred = 100
five_hundred = 500
print(f'{one_hundred} + {five_hundred} = {one_hundred + five_hundred}')

one_hundred = 'сто'
five_hundred = 'пятьсот'
print(f'{one_hundred} + {five_hundred} = {one_hundred + five_hundred}')
1
2
3
4
5
6
7

Результат вывода:

100 + 500 = 600
сто + пятьсот = стопятьсот
1
2

И обращение к элементам списка:

russian_alphabet = ['а', 'б', 'в', 'г', 'д', 'е', 'ё', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я']

print(f'"{russian_alphabet[-1]}" - последняя буква в алфавите.')
1
2
3

Результат вывода:

"я" - последняя буква в алфавите.
1

А также к элементам словаря по ключу:

favorite_songs = {
    'Тополиный пух': 'Иванушки international',
    'Город золотой': 'Аквариум',
    'Звезда по имени Солнце': 'Кино'
}

song = 'Город золотой'

print(f'"{song}" - одна из известных пеcен группы "{favorite_songs[song]}".')
1
2
3
4
5
6
7
8
9

Результат вывода:

"Город золотой" - одна из известных пеcен группы "Аквариум".
1

Хоть Python и позволяет вставлять очень сложные выражения внутрь f-строк, не злоупотребляйте этой возможностью. Иначе получится перегруженный код, в котором будет сложно разобраться. Сравните два эквивалентных примера:

print(f'Корни уравнения равны {(-b + (b**2 - 4*a*c)**(1/2)) / (2*a)} и {(-b - (b**2 - 4*a*c)**(1/2)) / (2*a)}')
1

и

d = b**2 - 4*a*c
x1 = (-b + d**(1/2)) / (2*a)
x2 = (-b - d**(1/2)) / (2*a)
print(f'Корни уравнения равны {x1} и {x2}')
1
2
3
4

Второй намного понятнее, хотя строк стало в четыре раза больше. Не так ли? Лучше придерживаться общего правила: f-строки используются только для форматирования вывода, а вычислять все выражения надо вне их. И вообще, не стоит экономить на количестве строчек кода, принося в жертву его читаемость.

Упражнения

  1. Научите Виту сообщать время в формате ЧЧ:ММ:СС (часы, минуты, секунды). Например На часах 19:28:06.
def print_time(hour, minute, second):
    print(...)      # аргумент должен содержать f-строку

print_time('19', '28', '06')
1
2
3
4
  1. Вите передали список listened (англ. listen, "слушать") с хронометражем прослушанных песен в секундах. Выведите на экран суммарную статистику: 'Вы прослушали N песен.', где N — длина списка listened.
def calc_stat(listened):  # от англ. calculate statistics, посчитать статистику
    # напишите код функции

print(calc_stat([193, 148, 210, 144, 174, 159, 163, 189, 230, 204]))
1
2
3
4
  1. Вите передали список listened (англ. listen, "слушать") с хронометражем прослушанных песен в секундах. Выведите на экран суммарную статистику:

'Вы прослушали N песен, общей продолжительностью M минут и S секунд.'

где:

  • N — длина списка listened;
  • M — количество целых минут общей продолжительности прослушанного;
  • S — остаток от целых минут.
def calc_stat(listened):  # от англ. calculate statistics, посчитать статистику
    # напишите код функции

print(calc_stat([193, 148, 210, 144, 174, 159, 163, 189, 230, 204]))
1
2
3
4

Запросы к друзьям

В предыдущей теме «Словари и множества» вы добавили в код персонального ассистента Виты данные о том, где живут ваши друзья. И она уже умеет отвечать на следующие запросы:

  • Сколько у меня друзей?
  • Кто все мои друзья?
  • Где все мои друзья?

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

  • Коля, ты где?
  • Соня, ты где?

Чтобы различать вопросы про отдельных друзей от общих вопросов к Вите, будем начинать общие вопросы с прямого обращения, вот так:

  • Вита, сколько у меня друзей?
  • Вита, кто все мои друзья?
  • Вита, где все мои друзья?

Тогда различать просто. Если вопрос начинается с имени "Вита", то это общий вопрос. А если с другого имени, то это вопрос про конкретного друга. Полагаем, правда, что у нас нет друзей по имени Вита. 😃

Упражнения

  1. Это код Виты, который вы последовательно писали на протяжении нескольких тем. Можете запустить его, вспомнить как выполняются запросы из списка queries.
DATABASE = {
    'Сергей': 'Омск',
    'Соня': 'Москва',
    'Миша': 'Москва',
    'Дима': 'Челябинск',
    'Алина': 'Красноярск',
    'Егор': 'Пермь',
    'Коля': 'Красноярск'
}

def process_query(query):
    # напишите код функции

def format_count_friends(count_friends):
    if count_friends == 1:
        return '1 друг'
    elif 2 <= count_friends <= 4:
        return f'{count_friends} друга'
    else:
        return f'{count_friends} друзей'


def process_vita(query):
    if query == 'сколько у меня друзей?':
        count_string = format_count_friends(len(DATABASE))
        return f'У тебя {count_string}'
    elif query == 'кто все мои друзья?':
        friends_string = ', '.join(DATABASE.keys())
        return f'Твои друзья: {friends_string}'
    elif query == 'где все мои друзья?':
        unique_cities = set(DATABASE.values())
        cities_string = ', '.join(unique_cities)
        return f'Твои друзья в городах: {cities_string}'
    else:
        return '<неизвестный запрос>'


def runner():
    queries = [
        'сколько у меня друзей?',
        'кто все мои друзья?',
        'где все мои друзья?',
        'кто виноват?'
    ]
    for query in queries:
        print(query, '-', process_vita(query))


runner()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

А. Отредактируйте список запросов queries. Все запросы должны начинаться с обращения Вита:

  • Вита, сколько у меня друзей?
  • ...

Б. Напишите функцию process_query(query). Значение параметра query должно быть обработано методом split(). Отделите имя в начале от тела запроса (т.е., от оставшейся части).

Если запрос начинается с имени "Вита", то вызовите функцию process_anfisa(), передав в неё тело запроса как параметр. И верните результат выполнения этой функции. Если запрос начинается с другого имени, то пока ничего не делайте — это отложим до следующей задачи.

В. Измените в функции runner() вызов process_anfisa() на вызов process_query().

  1. А. Напишите функцию process_friend(name, query) (англ. friend, "друг"), принимающую имя друга name и запрос query.
  • Если друга с указанным именем Н нет в списке, то функция должна вернуть сообщение об ошибке У тебя нет друга по имени Н.
  • Если запрос — "ты где?", то функция должна вернуть сообщения 'Н в городе Г', где Г определяется по данным словаря DATABASE.
  • Если запрос не "ты где?", а какой-то другой, то функция должна вернуть сообщение об ошибке <неизвестный запрос>.

Б. Допишите функцию process_query(). Если запрос начинается не с "Вита", а с другого имени, то вызовите функцию process_friend(name, query), передав в неё имя друга и тело запроса. И верните результат выполнения этой функции.

В. Добавьте в список queries новые запросы вида:

  • Коля, ты где?
  • Соня, что делать?
  • Антон, ты где?
DATABASE = {
    'Сергей': 'Омск',
    'Соня': 'Москва',
    'Миша': 'Москва',
    'Дима': 'Челябинск',
    'Алина': 'Красноярск',
    'Егор': 'Пермь',
    'Коля': 'Красноярск'
}

def process_friend(name, query):
    # напишите код функции

def process_query(query):
    # напишите код функции

def format_count_friends(count_friends):
    if count_friends == 1:
        return '1 друг'
    elif 2 <= count_friends <= 4:
        return f'{count_friends} друга'
    else:
        return f'{count_friends} друзей'

def process_anfisa(query):
    if query == 'сколько у меня друзей?':
        count_string = format_count_friends(len(DATABASE))
        return f'У тебя {count_string}'
    elif query == 'кто все мои друзья?':
        friends_string = ', '.join(DATABASE.keys())
        return f'Твои друзья: {friends_string}'
    elif query == 'где все мои друзья?':
        unique_cities = set(DATABASE.values())
        cities_string = ', '.join(unique_cities)
        return f'Твои друзья в городах: {cities_string}'
    else:
        return '<неизвестный запрос>'

def runner():
    queries = [
        'Вита, сколько у меня друзей?',
        'Вита, кто все мои друзья?',
        'Вита, где все мои друзья?',
        'Вита, кто виноват?',
        'Коля, ты где?',
        'Соня, что делать?',
        'Антон, ты где?'
    ]
    for query in queries:
        print(query, '-', process_query(query))

runner()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52