Создание своей функции
Создание функции
Понятие функции зародилось задолго до того, как появилось программирование. И в школе изучая алгебру мы уже сталкивались с функциями. Из учебников вы скорее всего помните такой пример функции:
math
f(x)=x^{2} + 1
А потом были задания, в которых надо нарисовать график функции и учитель показывал, как по очереди подставлять значения x для того, чтобы получить значение y и нарисовать на координатной сетке линию, плавно соединяющую полученные точки. Мы не очень сильно будем погружаться в математику, а точнее в математический анализ, который как раз изучает функции. Но в качестве исторической справки скажу, что понятие функции когда-то придумал Лейбниц и эта идея за долгое время видоизменялась пока не нашла свое место в программировании. В программировании понятие функции несколько отличается, от того, как это работает в математике, но такие функции как в примере легко повторить.
Обычно в программировании под функцией понимается какой-то участок кода, который выделен в отдельное место, и к которому можно обратиться по имени. Раньше функции еще называли подпрограммами, но если честно, то этот термин я в последний раз слышал в учебниках, а в реальности не помню, чтобы кто-то их моих коллег использовал это слово. В других языках программирования есть разделение на процедуры и функции и они отличаются тем возвращает ли код, который выполняет внутри функции хоть какой-то результат или нет.
В Python нет разделения на процедуры, подпрограммы, а есть только функции и методы. Метод — это тоже функция, которая дополнительно связана с объектом, и мы будем с ними подробно разбираться чуть позже, когда будем обсуждать классы и объектно-ориентированное программирование.
Определение функции звучит так:
Функция — это фрагмент программного кода, к которому можно обратиться из другого места программы.
По мере роста сложности программ становится ясно, что некоторые участки кода могут многократно повторяться. Кроме того, использование функций — это хороший способ структурирования программ. Вместо того чтобы писать многострочный вложенный блок внутри if/else, бывает лучше вынести тело блока в функцию и сделать код более читаемым.
Мы уже много раз вызывали встроенные функции и методы разных объектов, например max и len. Теперь настало время сделать свою функцию. Синтаксис определения функции выглядит следующим образом:
def <имя функции>(<аргументы>):
<тело функции>
Для того чтобы создать функцию надо использовать ключевое слово def (от слова definition — определение), указать имя функции и перечислить аргументы функции. После двоеточия с новой строки надо использовать отступ и продолжать писать с отступом до конца тела функции.
Прежде чем использовать функцию ее надо объявить, так же как и переменную. После этого ее можно вызывать, для этого надо к ней "обратиться", указав имя функции и в скобках перечислить аргументы, например len("строка"). Если у функции нет аргументов, то надо использовать пустые скобки <имя функции>().
Давайте создадим свою собственную функцию:
def hello():
print("Привет!")
Эта функция пока не принимает никаких аргументов и все что умеет делать это выводить на экрна строку Привет!.
Ключевое слово def обозначает что начинается блок объявления функции. hello — это имя функции, в Python — это имя переменной, которая ссылается на функцию. Если попытаться присвоить новое значение переменной hello, то старая связь будет удалена. Поэтому не используйте одинаковые имена для переменных и функций. Пустые скобки () говорят, что мы создаем функцию, которая не принимает никаких аргументов. Весь блок, начиная от ключевого слова def и до двоеточия (в нашем примере def hello()) называется объявлением функции. Он может быть достаточно большим, если функция принимает много аргументов или у функции длинное имя.
Поскольку имя функции — это на самом деле переменная, которая ссылается на функцию хранящаяся в памяти, то к именам функций такие же требования, как и к именам переменных. Но обычно имена функций делают длиннее, чем имена переменных для того, чтобы из названия было понятно, что она делает. Например, вполне уместно назвать функцию, которая отправляет сообщение пользователю notify_user.
Объявление функции может содержать объявление аргументов, которые функция получает. Если бы мы хотели сделать функцию, которая умеет приветствовать человека по имени, то можно было бы объявить, что функция может принимать аргумент name. Когда будет выполняться функция, то в теле функции переменная принимает значение, которое ей передали при вызове. То есть можно считать, что переменная с именем аргумента уже существует. Для того чтобы вызвать функцию надо написать ее имя и в скобках аргументы:
>>> def greet(name):
... print(f"Здравствуй, {name}!")
...
>>> greet("мир")
Здравствуй, мир!
>>> greet("биологическая форма жизни")
Здравствуй, биологическая форма жизни!
Результат выполнения функции, return
Если надо чтобы функция обрабатывала входящие данные и возвращала результат, то используется ключевое слово return. То, что находится справа от слова return выполнится и результат его вернется в виде результата функции. Например, если мы хотим реализовать математическую функцию, которую давали в начале лекции:
>>> def mathfunc(x):
... return x*x + 1
...
>>> print("f(0) =", mathfunc(0))
f(0) = 1
>>> print("f(1) =", mathfunc(1))
f(1) = 2
>>> print("f(3) =", mathfunc(3))
f(3) = 10
Результат выполнения функции можно присваивать переменной, или передавать другой функции, функции могут вызывать другие функции:
>>> def nice_draw(x):
... length = 60
... y = mathfunc(x)
... print(f"{' '*y}{'+'*(length-y)}")
...
>>> for i in range(-5, 6):
... nice_draw(i)
...
++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++
Тут мы воспользовались уже существующей функцией mathfunc которую вызвали внутри nice_func. А потом внутри цикла вызвали nice_func для каждого целого числа на промежутке от -5 до +5. Внутри nice_func мы воспользовались возможностью функции возвращать значение и поэтому создали специальную переменную y которой присвоили результат выполнения функции. А в цикле мы вызывали функцию, которая ничего не возвращала как свой результат, а печатала текст на экран. Обратите внимание, что результат выполнения nice_draw нас не интересовал, поэтому мы не присваиваем его никакой переменной.
Аргументы функции
Аргументы или параметры функции — это значения, которые передаются в функцию при ее вызове. Есть два типа аргументов функции:
- Позиционные — это те аргументы, которые просто требуют указания в определенном порядке
- Именованные — для этих аргументов обязательно требуется указать имя в формате
var=value
Мы уже пользовались и теми, и другими, например функция print() принимает позиционные аргументы:
>>> name = "Люк"
>>> print(name, "я твой отец!")
Люк я твой отец!
Но может так же принимать именованный параметр sep который будет использоваться для связи всех переданных позиционных параметров:
>>> print(name, "я твой отец!", sep=', ')
Люк, я твой отец!
У аргументов есть правила:
- Позиционные аргументы всегда идут первыми
- Порядок позиционных аргументов принципиально важен
- Функция может иметь как позиционные параметры, так и именованные параметры
- Именованные можно указывать в любой последовательности (после позиционных если они есть)
- Имена аргументов в определении функции должны соответствовать правилам имен переменных
Когда происходит вызов функции, то аргументы могут пропускаться:
- Позиционные пропускать нельзя
- Для именованных значение будет равно умолчанию данным в определении функции.
Пример определения и вызова функции только с позиционными параметрами:
>>> def positional(a, b, c):
... print(f"a={a}, b={b}, c={c}")
...
>>> positional(1, 2, 3)
a=1, b=2, c=3
>>> positional(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: positional() missing 2 required positional arguments: 'b' and 'c'
>>> positional(1, 2, 3, 4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: positional() takes 3 positional arguments but 4 were given
>>> positional(a=1, b=2, c=3)
a=1, b=2, c=3
>>> positional(a=1, c=2, b=3)
a=1, b=3, c=2
Функцию только с позиционными аргументами можно вызывать с синтаксисом функции с именованными аргументами. Но все равно лучше аргументы указывать в том порядке, в котором они были в определении функции.
Пример функции с позиционными и именованными параметрами:
>>> def mixed(a, b, c=10):
... print(f"a={a}, b={b}, c={c}")
...
>>> mixed(1, 2, 3)
a=1, b=2, c=3
>>> mixed(1, 2, c=3)
a=1, b=2, c=3
>>> mixed()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: mixed() missing 2 required positional arguments: 'a' and 'b'
Именованный аргумент можно использовать как позиционный, но все же лучше так не делать для улучшения читаемости кода.
Задание с кодом
В Python есть функция sum которая может получать на вход список (list), кортеж (tuple) и множество (set) и вычислять сумму элементов. Например, sum([1, 1, 1]) вернет 3. Но sum не может работать со списками, состоящими не из чисел. Например, sum([1, 'один', 1]) вернет ошибку.
Напишите код функции list_sum которая суммирует значение всех чисел в списке пропуская все типы кроме int и float.
