Функции в программировании

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

Функции можно сравнить с небольшими программками, которые сами по себе, т. е. автономно, не исполняются, а встраиваются в обычную программу. Нередко их так и называют – подпрограммы. Других ключевых отличий функций от программ нет. Функции также при необходимости могут получать и возвращать данные. Только обычно они их получают не с ввода (клавиатуры, файла и др.), а из вызывающей программы. Сюда же они возвращают результат своей работы.

Существует множество встроенных в язык программирования функций. С некоторыми такими в Python мы уже сталкивались. Это print(), input(), int(), float(), str(), type(). Код их тела нам не виден, он где-то «спрятан внутри языка». Нам же предоставляется только интерфейс – имя функции.

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

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

print("Сколько бананов и ананасов для обезьян?")
a = int(input())
b = int(input())
print("Всего", a+b, "шт.")

print("Сколько жуков и червей для ежей?")
a = int(input())
b = int(input())
print("Всего", a+b, "шт.")

print("Сколько рыб и моллюсков для выдр?")
a = int(input())
b = int(input())
print("Всего", a+b, "шт.")
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Результат выполнения может быть следующий:

Сколько бананов и ананасов для обезьян?
15
5
Всего 20 шт.
Сколько жуков и червей для ежей?
50
12
Всего 62 шт.
Сколько рыб и моллюсков для выдр?
16
8
Всего 24 шт.
1
2
3
4
5
6
7
8
9
10
11
12

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

Оператор def - объявление функции

В языке программирования Python функции определяются с помощью оператора def. Рассмотрим код:

def count_food():
    a = int(input())
    b = int(input())
    print("Всего", a+b, "шт.")
1
2
3
4

Это пример определения функции. Как и другие сложные инструкции вроде условного оператора и циклов функция состоит из заголовка и тела. Заголовок оканчивается двоеточием и переходом на новую строку. Тело имеет отступ.

Ключевое слово def сообщает интерпретатору, что перед ним определение функции. За def следует имя функции. Оно может быть любым, также как и всякий идентификатор, например, переменная. В программировании весьма желательно давать всему осмысленные имена. Так в данном случае функция названа «посчитатьЕду» в переводе на русский.

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

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

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

Рассмотрим полную версию программы с функцией:

def count_food():
    a = int(input())
    b = int(input())
    print("Всего", a+b, "шт.")

print("Сколько бананов и ананасов для обезьян?")
count_food()

print("Сколько жуков и червей для ежей?")
count_food()

print("Сколько рыб и моллюсков для выдр?")
count_food()
1
2
3
4
5
6
7
8
9
10
11
12
13

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

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

В языке Python определение функции должно предшествовать ее вызовам. Это связано с тем, что интерпретатор читает код строка за строкой и о том, что находится ниже по течению, ему еще неизвестно. Поэтому если вызов функции предшествует ее определению, то возникает ошибка (выбрасывается исключение NameError):

print("Сколько бананов и ананасов для обезьян?")
count_food()

print("Сколько жуков и червей для ежей?")
count_food()

print("Сколько рыб и моллюсков для выдр?")
count_food()

def count_food():
    a = int(input())
    b = int(input())
    print("Всего", a+b, "шт.")
1
2
3
4
5
6
7
8
9
10
11
12
13

Результат:

Сколько бананов и ананасов для обезьян?
Traceback (most recent call last):
  File "test.py", line 2, in <module>
    countFood()
NameError: name 'countFood' is not defined
1
2
3
4
5

Для многих компилируемых языков это не обязательное условие. Там можно определять и вызывать функцию в произвольных местах программы. Однако для удобочитаемости кода программисты даже в этом случае предпочитают соблюдать определенные правила.

Функции придают программе структуру

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

Пусть надо написать программу, вычисляющую площади разных фигур. Пользователь указывает, площадь какой фигуры он хочет вычислить. После этого вводит исходные данные. Например, длину и ширину в случае прямоугольника. Чтобы разделить поток выполнения на несколько ветвей, следует использовать оператор if-elif-else:

figure = input("1-прямоугольник, 2-треугольник, 3-круг: ")

if figure == '1':
    a = float(input("Ширина прямоугольника: "))
    b = float(input("Высота прямоугольника: "))
    print("Площадь: %.2f" % (a*b))
elif figure == '2':
    a = float(input("Основание треугольника: "))
    h = float(input("Высота треугольника: "))
    print("Площадь: %.2f" % (0.5 * a * h))
elif figure == '3':
    r = float(input("Радиус круга: "))
    print("Площадь: %.2f" % (3.14 * r**2))
else:
    print("Ошибка ввода")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Здесь нет никаких функций, и все прекрасно. Но напишем вариант с функциями:

def calculate_rectangle_area():
    a = float(input("Ширина: "))
    b = float(input("Высота: "))
    print("Площадь: %.2f" % (a*b))

def calculate_triangle_area():
    a = float(input("Основание: "))
    h = float(input("Высота: "))
    print("Площадь: %.2f" % (0.5 * a * h))

def calculate_circle_area():
    r = float(input("Радиус: "))
    print("Площадь: %.2f" % (3.14 * r**2))

figure = input("1-прямоугольник, 2-треугольник, 3-круг: ")
if figure == '1':
    calculate_rectangle_area()
elif figure == '2':
    calculate_triangle_area()
elif figure == '3':
    calculate_circle_area()
else:
    print("Ошибка ввода")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

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

Если нам понадобиться изменить код функциии, то не придется искать код во всей программе (представьте, что она состоит из тысяч строк кода как реальные программы). Мы пойдем к месту определения функций и изменим тело одной из них.

Упражнения

  1. Скопируйте следующий код с созданными функциями:

    def func_a():
        print("Step ...", end=" ")
    
    def func_b():
        print("Step ...", end=" ")
    
    def func_c():
        print("Step ...", end=" ")
    
    def func_d():
        print("Step ...", end=" ")
    
    def func_e():
        print("Step ...", end=" ")
    
    func_e()
    func_a()
    func_c()
    func_d()
    func_b()
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    • В строках print("Step ...", end=" ") замените троеточия: "..." на цифры от 1 до 5 таким образом, что бы результат вывода в консоль был следующим:
    Step 1 Step 2 Step 3 Step 4 Step 5
    
    1
    • В строках print("Step ...", end=" ") замените троеточия: "..." на цифры от 1 до 5 таким образом, что бы результат вывода в консоль был следующим:
    Step 5 Step 4 Step 3 Step 2 Step 1
    
    1
  2. Скопируйте следующий код с созданными функциями:

    def func_a():
        print("Step 5.", end=" ")
    
    def func_b():
        print("Step 1.", end=" ")
    
    def func_c():
        print("Step 2.", end=" ")
    
    def func_d():
        print("Step 4.", end=" ")
    
    def func_e():
        print("Step 3.", end=" ")
    
    ...
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    • Вместо троеточия допишите вызов функций в нужном порядке, чтобы результат вывода данного кода консоль был следующим:
    Step 1. Step 2. Step 3. Step 4. Step 5.
    
    1
    • Вызовите функции в нужном порядке, чтобы результат вывода данного кода в консоль был следующим:
    Step 5. Step 4. Step 3. Step 2. Step 1.
    
    1
  3. Скопируйте следующий код с созданными функциями:

    def func_a():
        print("Step ...", end=" ")
    
    def func_b():
        print("Step ...", end=" ")
    
    def func_c():
        print("Step ...", end=" ")
    
    def func_d():
        print("Step ...", end=" ")
    
    def func_e():
        print("Step ...", end=" ")
    
    func_d()
    print("Step ...", end=" ")
    func_b()
    func_c()
    print("Step ...", end=" ")
    func_e()
    func_a()
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    • В строках print("Step ...", end=" ") замените троеточия: "..." на цифры от 1 до 7 таким образом, что бы результат вывода в консоль был следующим:
    Step 1 Step 2 Step 3 Step 4 Step 5 Step 6 Step 7
    
    1
    • В строках print("Step ...", end=" ") замените троеточия: "..." на цифры от 1 до 7 таким образом, что бы результат вывода в консоль был следующим:
    Step 7 Step 6 Step 5 Step 4 Step 3 Step 2 Step 1
    
    1
  4. Скопируйте следующий код с созданными функциями:

    def func_a():
        print("Step ...", end=" ")
    
    def func_b():
        print("Step ...", end=" ")
    
    def func_c():
        func_b()
        print("Step ...", end=" ")
    
    def func_d():
        print("Step ...", end=" ")
    
    def func_e():
        print("Step ...", end=" ")
        func_a()
    
    func_c()
    print("Step ...", end=" ")
    func_e()
    print("Step ...", end=" ")
    func_d()
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    • В строках print("Step ...", end=" ") замените троеточия: "..." на цифры от 1 до 7 таким образом, что бы результат вывода в консоль был следующим:
    Step 1 Step 2 Step 3 Step 4 Step 5 Step 6 Step 7
    
    1
    • В строках print("Step ...", end=" ") замените троеточия: "..." на цифры от 1 до 7 таким образом, что бы результат вывода в консоль был следующим:
    Step 7 Step 6 Step 5 Step 4 Step 3 Step 2 Step 1
    
    1
  5. Скопируйте следующий код с созданными функциями:

    def func_a():
        print("Step 2.", end=" ")
    
    def func_b():
        print("Step 3.", end=" ")
    
    def func_c():
        func_b()
        print("Step 4.", end=" ")
    
    def func_d():
        print("Step 5.", end=" ")
    
    def func_e():
        print("Step 1.", end=" ")
        func_a()
    
    ...
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    • Вместо троеточия допишите вызов функций в нужном порядке, чтобы результат вывода данного кода консоль был следующим:
    Step 1. Step 2. Step 3. Step 4. Step 5.
    
    1
    • Вызовите функции в нужном порядке и внесите необходимые правки в исходных строках вызова функций, чтобы результат вывода данного кода в консоль был следующим :
    Step 5. Step 4. Step 3. Step 2. Step 1.
    
    1

    Примечание: достаточно поменять местами некоторые строки исходного кода внутри тела функций.

  6. Напишите программу: "Buy a fur coat!" Программа подобие диалога:

    • Программа выводит сообщение: "PC: - Buy a fur coat!"
    • После программа ждет ответного ввода с клавиатуры, например: "You: - No".
    • Далее программа выводит: PC: - Everyone says: "No", but you buy a fur coat!"
    • Если пользователь ничего не вводит, только нажимает "Enter", то программа отвечает: "PC: - Everyone is silent, but you buy a fur coat!"
    • Ответы могут быть другие, в произвольном порядке.
    • программа должны быть реализована с объявлением и вызовом функции, как повторяющейся части кода.
    • Реализуйте 7 повторов в диалоге вопрос-ответ.

    Пример работы программы может быть следующим:

    PC:  - Buy a fur coat!
    You: - I will not
    PC:  - Everyone says: "I will not", but you buy a fur coat!
    You: -
    PC:  - Everyone is silent, but you buy a fur coat!
    You: - Give me money.
    PC:  - Everyone says: "Give me money," but you buy a fur coat!
    You: - Good.
    PC:  - Everyone says "Good", but you buy a fur coat!
    ...
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  7. Основная ветка программы, не считая заголовков функций, состоит из одной строки кода. Это вызов функции test().

    • В функции test() запрашивается на ввод целое число. Если число положительное, то вызывается функция positive(), если число отрицательное, то вызывается функция negative().
    • тело функции positive() содержит команду вывода в консоль слово "Положительное".
    • тело функции negative() выводит в консоль слово "Отрицательное".

    Имеет ли значение порядок определения самих функций? То есть должны ли определения positive() и negative() предшествовать test() или должны следовать после него? Проверьте вашу гипотезу, поменяв функций местами. Попробуйте объяснить результат.