Функции
Существенная часть умения программирования — это умение проектировать программный продукт, в частности, разбивать задачу на подзадачи. В языке С нет деления подпрограмм на процедуры и функции, здесь вся программа состоит только из функций.
Функция — это совокупность объявлений и операторов, предназначенная для решения определенной задачи. Каждая функция имеет идентификатор — имя.
Даже «тело программы» — это функция с именем main, главная функция. В программе на С главная функция только одна, т. к. именно с нее, в каком бы месте она не находилась, начинается выполнение программы.
Имя (идентификатор) используется для вызова функции.
При вызове функции ей при помощи аргументов (формальных параметров) могут быть переданы некоторые значения (фактические параметры), используемые во время выполнения функции.
Функция может возвращать некоторое (одно!) значение. Это возвращаемое значение и есть результат выполнения функции, который при выполнении программы подставляется в точку вызова функции, где бы этот вызов ни встретился.
Допускается создание функций, не имеющих аргументов, а также функций, не возвращающих никаких значений. Действие таких функций может состоять в изменении значений глобальных переменных, выводе на печать текста или других побочных действиях.
Описание функции задает:
- тип возвращаемого значения;
- имя функции;
- типы и число формальных параметров;
- тело функции.
В определении функции также может быть указан класс памяти.
Пример
В данном примере определена функция с именем digit, имеющая один параметр с именем c и типом unsigned char. Функция возвращает целое значение, равное 1, если параметр функции является цифрой, или 0 в противном случае.
В языке С определение функции не обязательно предшествует ее вызову. Определения используемых функций могут находиться как перед местом вызова, так и ниже, или вообще находиться в другом файле.
Однако, чтобы компилятор мог осуществить проверку соответствия типов передаваемых фактических параметров типам формальных параметров, до вызова функции нужно поместить объявление функции — прототип.
Объявление функции похоже на определение функции, но тело функции отсутствует, а имена формальных параметров могут быть пропущены. Для функции, определенной в последнем примере, прототип может иметь вид
int digit(unsigned char);
Имя, тип возвращаемого значения и типы формальных параметров, задаваемые в определении функции, должны соответствовать типу в объявлении этой функции!
Для использования библиотечных функций, т. е. функции предварительно разработанных и записанных в библиотеки, требуется включить в программу их описания (заголовки), что осуществляется с помощью директивы #include.
Итак, определение функции имеет следующую форму:
Имя типа задает тип возвращаемого значения.
Функция не может возвращать массив или функцию!
Если выполнение функции заканчивается оператором return, содержащим некоторое выражение, то функция возвращает значение этого выражения. Оно вычисляется, преобразуется, если необходимо, к типу возвращаемого значения и возвращается в точку вызова функции в качестве результата.
Если оператор return не содержит выражения или выполнение функции завершается после выполнения ее последнего оператора (без выполнения оператора return), то возвращаемое значение не определено! На практике это означает, что программа поведет себя непредсказуемым образом. Если же по задумке разработчика функция и не должна ничего возвращать, то в качестве типа результата должен быть использован void.
Список формальных параметров — это последовательность объявлений формальных параметров, разделенная запятыми. Формальные параметры — это переменные, используемые внутри тела функции и получающие значение при вызове функции путем копирования в них значений соответствующих фактических параметров.
Список формальных параметров может заканчиваться запятой (,) или запятой с многоточием (, . ), это называется эллипсис, и означает, что число аргументов функции переменно. Над дополнительными аргументами не проводится контроль типов! Такие функции лучше не использовать на практике.
Если функция не использует параметров, то наличие круглых скобок обязательно, а вместо списка параметров рекомендуется указать слово void.
Порядок и типы формальных параметров должны быть одинаковыми в определении функции и во всех ее объявлениях. Типы фактических параметров при вызове функции должны быть совместимы с типами соответствующих формальных параметров.
Имена параметров используются в теле функции для доступа к переданным значениям.
Тело функции
Все переменные, объявленные в теле функции без указания класса памяти являются локальными. При вызове функции локальным переменным отводится память на стеке и производится их инициализация. Управление передается первому оператору тела функции, начинается ее выполнение, которое продолжается до тех пор, пока не встретится оператор return или последний оператор тела функции. Тогда управление возвращается в точку, следующую за точкой вызова, а локальные переменные исчезают, становятся недоступными. При новом вызове функции для локальных переменных память распределяется вновь, и поэтому старые значения локальных переменных теряются.
Параметры функции передаются по значению и могут рассматриваться как локальные переменные, для которых выделяется память при вызове функции и производится инициализация значениями фактических параметров. При выходе из функции их значения также теряются.
Поскольку передача параметров происходит по значению, в теле функции нельзя изменить значения фактических параметров. Однако, если в качестве параметра передать указатель на некоторую переменную, то используя операцию разыменования можно изменить значение этой переменной.
Пример
/* Неправильное использование параметров */
void swap(int x, int y)
int tmp = x;
x = y;
y = tmp;
>
В данной функции значения x и y, являющихся формальными параметрами, меняются местами, но поскольку эти переменные существуют только внутри функции change, значения фактических параметров, используемых при вызове функции, останутся неизменными.
Для того чтобы менялись местами значения фактических аргументов можно сделать так:
Пример
/* Правильное использование параметров */
void swap(int *x, int *y)
<
int tmp = *x;
*x = *y;
*y = tmp;
>
При вызове такой функции в качестве фактических параметров должны быть использованы не значения переменных, а их адреса:
Функция (программирование)
Функция от англ. function — фрагмент программного кода, к которому можно обратиться из другого места программы [1] .
Обращение к функции происходит по её имени (адрес первой инструкции, входящей в функцию). После выполнения функции управление возвращается обратно в адрес возврата, где данная функция была вызвана.
Функция может принимать параметры (аргументы) и должна возвращать некоторое значение. Частным случаем функции является процедура, которая ничего не возвращает. Она может быть объявлена или определена.
Объявление функции, включает в себя имя функции, список параметров (аргументов), тип возвращаемого значения.
Определение функции включает в себя имя функции, список параметров (аргументов), тип возвращаемого значения и тело функции.
Для того, чтобы использовать ранее определённую функцию, необходимо в требуемом месте программного кода указать имя функции и перечислить передаваемые в функцию параметры (аргументы).
Функция имеет локальную область видимости, поэтому все объявления внутри неё не будут влиять на глобальную область видимости. Исключение составляет использование заранее определённых глобальных переменных или объектов.
Параметры (аргументы) функции могут передаваться по ссылке или по значению. В случае передачи параметра (аргумента) по ссылке, функция будет работать с непосредственным объектом. И наоборот, в случае передачи параметра по значению, функция будет работать с копией объекта.
Виды функций
1) вложенные функции. Вложенной функцией называют функцию определённой в теле другой функции;
2) лямбда функции. Лямбда функцией называют функцию определённой в месте использования и не имеющей идентификатора (имени);
3) абстрактные (виртуальные) функции. Виртуальной функцией называют функцию, определённой в классе для последующей перегрузки в дочерних классах;
4) методы. Методом называют функцию, объявленной или определённой в классе;
5) рекурсивная функция. Рекурсивной называют функцию вызывающей саму себя [2] .
Функции в программировании
Функция в программировании представляет собой обособленный участок кода, который можно вызывать, обратившись к нему по имени, которым он был назван. При вызове происходит выполнение команд тела функции.
Функции можно сравнить с небольшими программками, которые сами по себе, то есть автономно, не исполняются, а встраиваются в обычную программу. Нередко их так и называют – подпрограммы. Других ключевых отличий функций от программ нет. Функции также при необходимости могут получать и возвращать данные. Только обычно они их получают не с ввода (клавиатуры, файла и др.), а из вызывающей программы. Сюда же они возвращают результат своей работы.
Существует множество встроенных в язык программирования функций. С некоторыми такими в Python мы уже сталкивались. Это print() , input() , int() , float() , str() , type() . Код их тела нам не виден, он где-то «спрятан внутри языка». Нам же предоставляется только интерфейс – имя функции.
С другой стороны, программист всегда может определять свои функции. Их называют пользовательскими. В данном случае под «пользователем» понимают программиста, а не того, кто пользует программу. Разберемся, зачем нам эти функции, и как их создавать.
Предположим, надо три раза подряд запрашивать на ввод пару чисел и складывать их. С этой целью можно использовать цикл:
i = 0 while i 3: a = int(input()) b = int(input()) print(a + b) i += 1
Однако, что если перед каждым запросом чисел, надо выводить надпись, зачем они нужны, и каждый раз эта надпись разная. Мы не можем прервать цикл, а затем вернуться к тому же циклу обратно. Придется отказаться от него, и тогда получится длинный код, содержащий в разных местах одинаковые участки:
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, "шт.")
Пример исполнения программы:
Сколько бананов и ананасов для обезьян? 15 5 Всего 20 шт. Сколько жуков и червей для ежей? 50 12 Всего 62 шт. Сколько рыб и моллюсков для выдр? 16 8 Всего 24 шт.
Внедрение функций позволяет решить проблему дублирования кода в разных местах программы. Благодаря им можно исполнять один и тот же участок кода не сразу, а только тогда, когда он понадобится.
Определение функции. Оператор def
В языке программирования Python функции определяются с помощью оператора def . Рассмотрим код:
def count_food(): a = int(input()) b = int(input()) print("Всего", a + b, "шт.")
Это пример определения функции. Как и другие сложные инструкции вроде условного оператора и циклов функция состоит из заголовка и тела. Заголовок оканчивается двоеточием и переходом на новую строку. Тело имеет отступ.
Ключевое слово def сообщает интерпретатору, что перед ним определение функции. За def следует имя функции. Оно может быть любым, также как и всякий идентификатор, например, переменная. В программировании весьма желательно давать всему осмысленные имена. Так в данном случае функция названа «посчитать_еду» в переводе на русский.
После имени функции ставятся скобки. В приведенном примере они пустые. Это значит, что функция не принимает никакие данные из вызывающей ее программы. Однако она могла бы их принимать, и тогда в скобках были бы указаны так называемые параметры.
После двоеточия следует тело, содержащее инструкции, которые выполняются при вызове функции. Следует различать определение функции и ее вызов. В программном коде они не рядом и не вместе. Можно определить функцию, но ни разу ее не вызвать. Нельзя вызвать функцию, которая не была определена. Определив функцию, но ни разу не вызвав ее, вы никогда не выполните ее тела.
Вызов функции
Рассмотрим полную версию программы с функцией:
def count_food(): a = int(input()) b = int(input()) print("Всего", a+b, "шт.") print("Сколько бананов и ананасов для обезьян?") count_food() print("Сколько жуков и червей для ежей?") count_food() print("Сколько рыб и моллюсков для выдр?") count_food()
После вывода на экран каждого информационного сообщения осуществляется вызов функции, который выглядит просто как упоминание ее имени со скобками. Поскольку в функцию мы ничего не передаем скобки опять же пустые. В приведенном коде функция вызывается три раза.
Когда функция вызывается, поток выполнения программы переходит к ее определению и начинает исполнять ее тело. После того, как тело функции исполнено, поток выполнения возвращается в основной код в то место, где функция вызывалась. Далее исполняется следующее за вызовом выражение.
В языке Python определение функции должно предшествовать ее вызовам. Это связано с тем, что интерпретатор читает код строка за строкой и о том, что находится ниже по течению, ему еще неизвестно. Поэтому если вызов функции предшествует ее определению, то возникает ошибка (выбрасывается исключение NameError ):
print("Сколько бананов и ананасов для обезьян?") count_food() print("Сколько жуков и червей для ежей?") count_food() print("Сколько рыб и моллюсков для выдр?") count_food() def count_food(): a = int(input()) b = int(input()) print("Всего", a + b, "шт.")
Сколько бананов и ананасов для обезьян? Traceback (most recent call last): File "test.py", line 2, in count_food() NameError: name 'count_food' is not defined
Для многих компилируемых языков это не обязательное условие. Там можно определять и вызывать функцию в произвольных местах программы. Однако для удобочитаемости кода программисты даже в этом случае предпочитают соблюдать определенные правила.
Функции придают программе структуру
Польза функций не только в возможности многократного вызова одного и того же кода из разных мест программы. Не менее важно, что благодаря им программа обретает истинную структуру. Функции как бы разделяют ее на обособленные части, каждая из которых выполняет свою конкретную задачу.
Пусть надо написать программу, вычисляющую площади разных фигур. Пользователь указывает, площадь какой фигуры он хочет вычислить. После этого вводит исходные данные. Например, длину и ширину в случае прямоугольника. Чтобы разделить поток выполнения на несколько ветвей, следует использовать оператор 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("Ошибка ввода")
Здесь нет никаких функций, и все прекрасно. Но напишем вариант с функциями:
def rectangle(): a = float(input("Ширина: ")) b = float(input("Высота: ")) print("Площадь: %.2f" % (a * b)) def triangle(): a = float(input("Основание: ")) h = float(input("Высота: ")) print("Площадь: %.2f" % (0.5 * a * h)) def circle(): r = float(input("Радиус: ")) print("Площадь: %.2f" % (3.14 * r ** 2)) figure = input("1-прямоугольник, 2-треугольник, 3-круг: ") if figure == '1': rectangle() elif figure == '2': triangle() elif figure == '3': circle() else: print("Ошибка ввода")
Он кажется сложнее, а каждая из трех функций вызывается всего один раз. Однако из общей логики программы как бы убраны и обособлены инструкции для нахождения площадей. Программа теперь состоит из отдельных «кирпичиков Лего». В основной ветке мы можем комбинировать их как угодно. Она играет роль управляющего механизма.
Если нам когда-нибудь захочется вычислять площадь треугольника по формуле Герона, а не через высоту, то не придется искать код во всей программе (представьте, что она состоит из тысяч строк кода как реальные программы). Мы пойдем к месту определения функций и изменим тело одной из них.
Если понадобиться использовать эти функции в какой-нибудь другой программе, то мы сможем импортировать их туда, сославшись на данный файл с кодом (как это делается в Python, будет рассмотрено позже).
Практическая работа
В программировании можно из одной функции вызывать другую. Для иллюстрации этой возможности напишите программу по следующему описанию.
Основная ветка программы, не считая заголовков функций, состоит из одной строки кода. Это вызов функции test() . В ней запрашивается на ввод целое число. Если оно положительное, то вызывается функция positive() , тело которой содержит команду вывода на экран слова «Положительное». Если число отрицательное, то вызывается функция negative() , ее тело содержит выражение вывода на экран слова «Отрицательное».
Понятно, что вызов test() должен следовать после определения функций. Однако имеет ли значение порядок определения самих функций? То есть должны ли определения positive() и negative() предшествовать test() или могут следовать после него? Проверьте вашу гипотезу, поменяв объявления функций местами. Попробуйте объяснить результат.
Примеры решения и дополнительные уроки в pdf-версии курса
X Скрыть Наверх
Python. Введение в программирование
Функции в Python для начинающих
В этой части мы изучим функции — составные инструкции, которые могут принимать данные ввода, выполнять указания и возвращать данные вывода. Функции позволяют определять и повторно использовать определенную функциональность в компактной форме.
Вызвать функцию — значит передать ей входные данные, необходимые для выполнения и возвращения результата. Когда вы передаете функции входные данные, это называется передача параметра функции.
Функции в Python похожи на математические функции из алгебры. Например, в алгебре функция определяется как-то так:
f(x) = x * 2
Левая часть определяет функцию f , принимающую один параметр, x . А правая часть — это определение функции, которое использует переданный параметр x , чтобы произвести вычисление и вернуть результат. В этом случае значением функции является ее параметр, умноженный на два.
Как в Python функция записывается следующим образом: имя_функции(параметры_через_запятую) . Чтобы вызвать функцию, после ее имени нужно указать круглые скобки и поместить внутрь параметры, отделив каждый из них запятой. Для создания функций в Python выберите ее имя, определите параметры, укажите, что функция должна делать и какое значение возвращать.
def имя_функции(параметры): определениие_функции
Математическая функция f(x) = x * 2 в Python будет выглядеть вот так:
def f(x): return x * 2
Ключевое слово def сообщает Python, что вы определяете функцию. После def вы указываете имя функции; оно должно отвечать тем же правилам, что и имена переменных. Согласно конвенции, в имени функции нельзя использовать заглавные буквы, а слова должны быть разделены подчеркиванием вот_так .
Как только вы присвоили своей функции имя, укажите после него круглые скобки. Внутри скобок должен содержаться один или несколько параметров.
После скобок ставится двоеточие, а новая строка начинается с отступа в четыре пробела. Любой код с отступом в четыре пробела после двоеточия является телом функции. В этом случае тело нашей функции состоит только из одной строки:
return x * 2
Ключевое слово return используется для определения значения, которое функция возвращает при вызове.
Чтобы вызвать функцию в Python, мы используем синтаксис имя_функции(параметры, через, запятую) .
Ниже описан вызов функции f из предыдущего примера с параметром 2 .
Консоль ничего не вывела. Можно сохранить вывод вашей функции в переменной и передать ее функции print .
# Продолжение# предыдущего примераdef f(x): return x * 2result = f(2)print(result) # 4
Вы можете сохранить результат, возвращаемый вашей функцией, в переменной и использовать это значение в программе позднее.
def f(x): return x + 1 z = f(4)if z == 5: print("z равно 5")else: print ("z не равно 5")
У функции может быть один параметр, несколько параметров или вообще их не быть. Чтобы определить функцию, не требующую параметров, оставьте круглые скобки пустыми.
def f(): return 1 + 1 result = f()print(result) # 2
Если хотите, чтобы функция принимала больше одного параметра, отделите каждый параметр в скобках запятой.
def f(x, y, z): return x + y + z result = f(1, 2, 3)print(result) # 6
Наконец, функция не обязана содержать инструкцию return. Если функции нечего возвращать, она возвращает значение None .
def f(): z = 1 + 1result = f()print(result) # None
Обязательные и необязательные параметры ¶
Функция может принимать параметры двух типов. Те, что встречались вам до этого, называются обязательными параметрами. Когда пользователь вызывает функцию, он должен передать в нее все обязательные параметры, иначе Python сгенерирует исключение.
В Python есть и другой вид параметров — опциональные. Опциональные параметры определяются с помощью следующего синтаксиса: имя_функции(имя_параметра = значение_параметра) . Как и обязательные, опциональные параметры нужно отделять запятыми. Ниже приведен пример функции, в коде которой используется опциональный параметр.
def f(x=2): return x**x print (f()) # 4print (f(4)) # 16
Сначала функция вызывается без передачи параметра. Так как параметр необязательный, x автоматически становится равен 2 , и функция возвращает 4 .
Затем та же функция вызывается с параметром 4 . То есть x будет равен 4 и функция вернет 16 . Вы можете определить функцию, которая принимает как обязательные, так и опциональные параметры, но обязательные нужно определять в первую очередь.
def add(x, y=10): return x + yresult = add(2)print(result)