Функции

Функция — блок кода для выполнения определенной задачи, который можно использовать многократно в разных частях программы. Существует множество встроенных в Python готовых функций. Некоторые вы уже применяли ранее: print(), str(), int(), float(), len().

Создание функции называется определение. Оно начинается с ключевого слова def (от англ. definition, «определение»), затем идут имя функции, её аргументы, или параметры в круглых скобках и двоеточие. Начиная со следующей строки, с отступом в 4 пробела от начала, записывают тело функции — код, который она выполняет. Обращение к функции называется вызов функции. Функция вызывается по имени, при вызове ей передают аргументы, с которыми она должна что-то сделать.

Напишем приветствие как функцию:

# код функции say_hello
def say_hello(current_hour):
    if current_hour <= 5 or current_hour >= 23:
        print('Доброй ночи!')
    elif current_hour >= 6 and current_hour <= 11:
        print('Доброе утро!')
    elif current_hour >= 12 and current_hour <= 17:
        print('Добрый день!')
    elif current_hour >= 18 and current_hour <= 22:
        print('Добрый вечер!')

# основной код
say_hello(4)  # вызов функции с аргументом 4
print('------')
say_hello(10)  # вызов функции с аргументом 10
print('------')
say_hello(15)  # ещё один вызов функции
print('------')
say_hello(20)  # и ещё один вызов функции
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Доброй ночи!
------
Доброе утро!
------
Добрый день!
------
Добрый вечер!
1
2
3
4
5
6
7

Создали функцию с именем say_hello (англ. say hello, "поздороваться"). В любом месте программы при вызове say_hello() будет выводиться на экран приветствие с текстом, зависящим от аргумента current_hour (англ. current hour, "текущий час").

Упражнения

  1. На основе заготовленного кода напишите функцию print_friends_count() для вывода количества друзей. Аргументом сделайте friends_count. Вызовите эту функцию не менее трёх раз с разными аргументами. Значениями friends_count могут быть любые натуральные числа.
def print_friends_count(friends_count):
    if friends_count == 1:
        print('У тебя 1 друг')
    elif 2 <= friends_count <= 4:
        print('У тебя ' + str(friends_count) + ' друга')
    elif friends_count >= 5:
        print('У тебя ' + str(friends_count) + ' друзей')
1
2
3
4
5
6
7
  1. Напишите цикл для запусков print_friends_count() c аргументами от 1 до 10. Проследите изменения выведенных надписей.

Упражнения tkinter

  1. Напишите оконное приложение выводящее список количества друзей.

  2. Напишите оконное приложение с полем ввода количества друзей. Кнопкой при нажатии на которую выводится сообщение о количестве друзей.

Аргументы функции

В Python аргументам функций может быть присвоено значение по умолчанию. Оно подставляется, когда при вызове функции вы не оставляете насчёт аргументов никаких инструкций.

# код функции say_hello
def say_hello(current_hour, name=''):
    if current_hour <= 5 or current_hour >= 23:
        hello_message = 'Доброй ночи'
    elif current_hour >= 6 and current_hour <= 11:
        hello_message = 'Доброе утро'
    elif current_hour >= 12 and current_hour <= 17:
        hello_message = 'Добрый день'
    elif current_hour >= 18 and current_hour <= 22:
        hello_message = 'Добрый вечер'
    if name != '':
        print(hello_message + ', ' + name + '!')
    else:
        print(hello_message + '!')

# основной код
say_hello(10, 'Тимур')
print('------')
say_hello(14, 'Елена')
print('------')
say_hello(20)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Доброе утро, Тимур!
------
Добрый день, Елена!
------
Добрый вечер!
1
2
3
4
5

Функция say_hello() принимает два аргумента — current_hour и name (англ. name, "имя"), которому задано значение по умолчанию. При вызове только с одним аргументом current_hour значением второго аргумента name станет пустая строка.

При вызове функции можно явно указывать, какому аргументу какое значение соответствует. В таком случае порядок следования аргументов в скобках роли не играет.

say_hello(current_hour=10, name='Тимур')
print('------')
say_hello(name='Елена', current_hour=14)
print('------')
say_hello(current_hour=20)
1
2
3
4
5
Доброе утро, Тимур!
------
Добрый день, Елена!
------
Добрый вечер!
1
2
3
4
5

Упражнения

  1. Допишите код функции print_friends_count(), добавьте аргумент name со значением по умолчанию. Если вы при вызове передаёте функции имя, она должна вывести на экран строку вида '{имя}, у тебя N друзей', если нет — тогда просто 'У тебя N друзей'.

  2. Анфиса может анализировать списки. Например, подсчитывать дни, когда в вашем городе или в городах ваших друзей стояла хорошая погода.

Есть списки средних дневных температур в Москве за май 2017 и 2018 годов. Создайте функцию comfort_count(temperatures) для подсчёта в переданном списке комфортных дней — дней с температурой воздуха от 22 до 26 градусов включительно.

Функция в результате работы должна вывести на экран строку 'Количество комфортных дней в этом месяце: N', где N — результат подсчёта в цикле с условием. Сначала посчитайте приятные дни в мае 2017-го года, а потом — в мае 2018-го.

may_2017 = [24, 26, 15, 10, 15, 19, 10, 1, 4, 7, 7, 7, 12, 14, 17, 8, 9, 19, 21, 22, 11, 15, 19, 23, 15, 21, 16, 13, 25, 17, 19]
may_2018 = [20, 27, 23, 18, 24, 16, 20, 24, 18, 15, 19, 25, 24, 26, 19, 24, 25, 21, 17, 11, 20, 21, 22, 23, 18, 20, 23, 18, 22, 23, 11]

# допишите код ниже
1
2
3
4

Разбиение на функции

В больших проектах, написанных на Python, принято выносить весь повторяющийся код в отдельные функции перед телом основной программы. Посмотрим на пример:

# код функции say_hello
def say_hello(current_hour):
    if current_hour <= 5 or current_hour >= 23:
        print('Доброй ночи!')
    elif current_hour >= 6 and current_hour <= 11:
        print('Доброе утро!')
    elif current_hour >= 12 and current_hour <= 17:
        print('Добрый день!')
    elif current_hour >= 18 and current_hour <= 22:
        print('Добрый вечер!')

# перенесли основной код внутрь функции runner()
def runner():
    say_hello(4)
    say_hello(10)
    say_hello(15)
    say_hello(20)

# в теле программы остаётся только один вызов:
runner()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Функция say_hello() содержит основную логику, а runner() (от англ. run, "запускать") выполняет роль управляющего механизма. Такое разделение придаёт коду программы аккуратный внешний вид, делает его более выразительным, упрощает чтение.

Упражнения

  1. Подготовьте код Виты к использованию на сервере.
  • Напишите функцию process_query() (англ. process query, «обработать запрос»). Перенесите в неё весь код из тела основной программы. Эта функция будет принимать на вход запросы пользователя и выдавать ответ на них. Пока она может обработать всего один запрос — сообщить количество друзей.
  • Добавьте вызов функции process_query() в тело основной программы.
FRIENDS = ['Серёга', 'Соня', 'Дима', 'Алина', 'Егор']

def print_friends_count(friends_count):
    if friends_count == 1:
        print('У тебя 1 друг')
    elif 2 <= friends_count <= 4:
        print('У тебя ' + str(friends_count) + ' друга')
    elif friends_count >= 5:
        print('У тебя ' + str(friends_count) + ' друзей')

# перенесите в функцию process_query() вот этот код:
print("Привет, я Анфиса!")
count = len(FRIENDS)
print_friends_count(count)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  1. На серверы приходит множество запросов — от разных пользователей или от других серверов. Измените функцию process_query() (обработчик запроса), чтобы она поддерживала несколько разных запросов, а не только один.
  • Добавьте аргумент query в функцию process_query(). Этот аргумент будет сообщать, какой именно запрос необходимо обработать.
  • В начало функции process_query() добавьте проверку значения переменной query: если значение равно 'Сколько у меня друзей?' — выведите ответ на этот вопрос, как в предыдущем задании;
  • в противном случае — выведите '<неизвестный запрос>'. Добавьте вызов process_query('Сколько у меня друзей?') в основное тело программы. Добавьте ещё один вызов process_query('Как меня зовут?') в основное тело программы.
  1. Доработайте программу.
  • Добавьте в функцию process_query() обработку ещё одного запроса 'Кто все мои друзья?'. В ответ нужно выводить на экран Твои друзья: {список_друзей}, где {список_друзей} — строка, состоящая из списка друзей, разделённых запятой и пробелом.
  • Добавьте вызов process_query('Кто все мои друзья?') в тело основной программы.

Возврат значений из функции

Пока что все наши функции печатали результаты своей работы на экран. Но обычно задача функции не сводится к выступлениям в печати. Как правило, это код, производящий специальные вычисления. Он не выводит результаты на экран, а возвращает их как значения. Значение вернётся в вызывающий код, и там будет использовано. Например, сохранено в переменной. Если программе нужно, к примеру, несколько раз посчитать одно и то же, эти вычисления поручают особым функциям:

# функция для вычисления периметра прямоугольника
# от англ. calculate, "вычислять"
def calc_perimeter(side_a, side_b):
    return (side_a + side_b) * 2

# функция для вычисления площади прямоугольника
def calc_square(side_a, side_b):
    return side_a * side_b

# Посчитаем периметр и площадь прямоугольника со сторонами 8 и 10 метров
a = 8
b = 10
p = calc_perimeter(a, b)
s = calc_square(a, b)
print('Периметр прямоугольника равен ' + str(p) + ' м.')
print('Площадь прямоугольника равна ' + str(s) + ' кв. м.')

# можем произвести расчёты и для другого прямоугольника
p = calc_perimeter(3, 4)
print('Периметр прямоугольника равен ' + str(p) + ' м.')

# Возвращённое значение не обязательно сохранять в переменной.
# Можно сразу вывести на экран:
print('Площадь прямоугольника равна ' + str(calc_square(3, 4)) + ' кв. м.')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Периметр прямоугольника равен 36 м.
Площадь прямоугольника равна 80 кв.м.
Периметр прямоугольника равен 14 м.
Площадь прямоугольника равна 12 кв.м.
1
2
3
4

Ключевое слово return (англ. «возвращать») указывает, какое значение функция вернёт основному коду.

Упражнения

  1. Доработаем программу подсчёта комфортных дней в мае.
  • Измените функцию comfort_count(), чтобы она не печатала количество комфортных дней, а возвращала.
  • Чтобы увидеть результат выполнения функции, напечатайте его в основном коде командой print(comfort_count(may_2017)).
may_2018 = [20, 27, 23, 18, 24, 16, 20, 24, 18, 15, 19, 25, 24, 26, 19, 24, 25, 21, 17, 11, 20, 21, 22, 23, 18, 20, 23, 18, 22, 23, 11]
may_2017 = [24, 26, 15, 10, 15, 19, 10, 1, 4, 7, 7, 7, 12, 14, 17, 8, 9, 19, 21, 22, 11, 15, 19, 23, 15, 21, 16, 13, 25, 17, 19]


# в этой функции не должно быть вызова print
def comfort_count(temperatures):
    count = 0
    for temp in temperatures:
        if 22 <= temp <= 26:
            count += 1
    return count

print(comfort_count(may_2017))
# здесь нужна команда печатать результат, возвращённый функцией comfort_count()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Вызов функции из функции

Функцию можно вызвать не только из основного кода, но и из другой функции.

# это первая функция, она только возвращает значение
# выражение \n означает перевод строки
def Jack():
    return 'в доме, который построил Джек.\n'

# это вторая функция, она вызывает первую
# и возвращает свою строку вместе с результатом функции Jack()
def wheat():
    return 'которая в тёмном чулане хранится\n' + Jack()

# а это третья функция, которая вызывает вторую,
# которая вызывает первую
def bird():
    return 'которая часто ворует пшеницу,\n' + wheat()

print('Вот дом, который построил Джек.\n')
print('А это пшеница, ' + wheat())
print('А это весёлая птица-синица, ' + bird())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Вот дом, который построил Джек.

А это пшеница, которая в тёмном чулане хранится
в доме, который построил Джек.

А это весёлая птица-синица, которая часто ворует пшеницу,
которая в тёмном чулане хранится
в доме, который построил Джек.
1
2
3
4
5
6
7
8

Хорошая привычка — выделять вычисления и вывод в отдельные функции, чтобы печать результатов не была разбросана по всему коду.

# здесь вычисления периметра и площади прямоугольника
def calc_perimeter(side_a, side_b):
    return (side_a + side_b) * 2

def calc_square(side_a, side_b):
    return side_a * side_b

# здесь подготовка результата
def show_info(side_a, side_b):
    p = calc_perimeter(side_a, side_b)
    s = calc_square(side_a, side_b)
    text = 'Периметр равен ' + str(p) + ' м., '
    text += 'а площадь - ' + str(s) + ' кв.м.'
    return text

# здесь все вызовы print()
def runner():
    print(show_info(8, 10))
    print(show_info(3, 4))

runner()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Периметр равен 36 м., а площадь - 80 кв.м.
Периметр равен 14 м., а площадь - 12 кв.м.
1
2

Если бы мы ошиблись и забыли вернуть строку text из функции show_info(), то вывод получился бы странный:

# здесь подготовка результата
def show_info(side_a, side_b):
    p = calc_perimeter(side_a, side_b)
    s = calc_square(side_a, side_b)
    text = 'Периметр равен ' + str(p) + ' м., '
    text += 'а площадь - ' + str(s) + ' кв.м.'

# здесь все вызовы print()
def runner():
    print(show_info(8, 10))
    print(show_info(3, 4))
1
2
3
4
5
6
7
8
9
10
11
None
None
1
2

Что такое None здесь? Это специальное значение в Python, и оно обозначает... ничего (англ. none, "ничто"). Если значение какой-нибудь переменной равно None, обычно это значит, что она не определена, не имеет никакого значения. Функция runner() печатает результаты вызовов функции show_info(). Так как в ней нет return, то она ничего не возвращает, и print() печатает это самое ничего.

Упражнения

  1. Измените код Виты. Оставьте вывод на экран, т.е. вызовы функции print(), только в одном месте — в основном теле программы. Эти вызовы уже написаны в предварительном коде задания. Все прошлые выводы на экран — в функциях show_count_friends() и process_query() — замените на возвращения результатов из функции оператором return.