Функция — блок кода в виде подпрограммы с именем, который решает какую-либо задачу.
Преимущества использования функций:
В Python есть несколько типов функций:
Здесь мы рассмотрим именно пользовательские функции.
def my_function(a, b):
function_block
return expression
Для того, чтобы создать функцию в Python, нужно использовать ключевое слово def
, когда интерпретатор дойдет до него, то он поймет, что вы начинаете определять функцию.
Далее следует указать имя функции и круглые скобки, в которых обозначаются параметры функции (они необязательны). Потом идет двоеточие и с отступом тело функции.
Если функция должна что-то возвращать, то используется оператор return
. Возврат из функции может быть только один.
С объявлением функции разобрались, теперь давайте разберем, как ее можно вызывать.
После того, как функция создана, мы можем ее вызвать, но вызов функции обязательно должен быть после ее объявления иначе будет ошибка, т.к. интерпретатор еще не не знает об этой функции.
Для того, чтобы вызвать функцию используйте ее имя и круглые скобки:
def my_function():
print('Python')
my_function()
#Python
Мы создали функцию my_function()
, которая просто выводит ‘Python’, далее ниже в коде мы вызвали эту функции, просто обратившись к ней по ее имени.
В результате мы получили вывод ‘Python’.
Теперь создадим функцию, которая возвращает результат своей работы с помощью оператора return
:
def my_sum():
a = 1
b = 1
return a + b
print(my_sum())
#2
В созданной функции my_sum()
мы складываем переменные a
и b
, далее с помощью return
возвращаем результат работы функции, т.е. сумму и после этого функцией print()
выводим результат работы нашей функции.
Также результат работы функции можно не просто выводить, но и присваивать переменным, а дальше уже использовать этот результат, как душе угодно.
Присвоим переменной результат функции из предыдущего примера:
def my_sum():
a = 1
b = 1
return a + b
a = my_sum()
print(a)
#2
Но помимо этого, мы можем присваивать переменной еще и саму функцию, а не только ее значение:
def my_sum():
a = 1
b = 1
return a + b
a = my_sum
print(a())
#2
Аргументы функции — значение, которое передается в функцию.
Параметр функции — это переменная, которой присваивается входящее в функцию значение.
def my_sum(a, b): #a, b - параметры функции
return a + b
my_sum(1, 2) #1, 2 - аргументы функции
В свою очередь аргументы функции делятся на:
Позиционные аргументы передаются в функцию в том же порядке, в котором они определены при создании функции.
Порядок передачи аргументов определяет, какое значение получит каждый параметр функции.
На примере, будет понятней, создадим функцию, которая получает имя и фамилию, и выводит приветствие:
def hello_user(first_name, last_name):
print(f'first_name = {first_name}, last_name = {last_name}')
print(f'Привет, {first_name}!')
hello_user('Роман', 'Пупкин')
#first_name = Роман, last_name = Пупкин
#Привет, Роман!
Мы передаем позиционные аргументы ‘Роман’, ‘Пупкин’, которые попадают в параметры функции first_name
, last_name
. После чего выводятся через print()
.
А что будет, если мы поменяем местами аргументы на ‘Пупкин’, ‘Роман’:
def hello_user(first_name, last_name):
print(f'first_name = {first_name}, last_name = {last_name}')
print(f'Привет, {first_name}!')
hello_user('Пупкин', 'Роман')
#first_name = Пупкин, last_name = Роман
#Привет, Пупкин!
Как видно, теперь аргумент ‘Пупкин’ попал в параметр first_name
, а ‘Роман’ в last_name
.
Т.е. нарушился порядок следования аргументов. При работе с позиционными аргументами нужно очень внимательно следить за порядком, иначе возможны неожиданные результаты.
Именованный аргумент — это пара ‘имя=значение’, которая передается в функцию.
Т.е. при вызове функции указывается имя параметра, за затем значение, которое хотите ему присвоить.
Это избавляет от лишних проблем с соблюдением порядка аргументов при вызове функции.
def hello_user(first_name, last_name):
print(f'first_name = {first_name}, last_name = {last_name}')
print(f'Привет, {first_name}!')
hello_user(first_name='Роман', last_name='Пупкин')
#first_name = Роман, last_name = Пупкин
#Привет, Роман!
Даже если передать аргументы в другом порядке, все отработает, так, как было задумано изначально:
def hello_user(first_name, last_name):
print(f'first_name = {first_name}, last_name = {last_name}')
print(f'Привет, {first_name}!')
hello_user(last_name='Пупкин', first_name='Роман')
#first_name = Роман, last_name = Пупкин
#Привет, Роман!
При вызове функции можно использовать одновременно и позиционные аргументы и именованные:
def hello_user(first_name, last_name):
print(f'first_name = {first_name}, last_name = {last_name}')
print(f'Привет, {first_name}!')
hello_user('Пупкин', last_name='Роман')
#first_name = Пупкин, last_name = Роман
#Привет, Пупкин!
Но важно помнить, что сначала идут позиционные аргументы, а после них уже именованные, иначе будет ошибка:
def hello_user(first_name, last_name):
print(f'first_name = {first_name}, last_name = {last_name}')
print(f'Привет, {first_name}!')
hello_user(last_name='Роман', 'Пупкин')
#Syntax Error: positional argument follows keyword argument
При создании функции, мы можем записать параметр, который будет по-умолчанию равен чему-либо:
def hello_user(first_name, last_name, log=True):
if log:
print(f'first_name = {first_name}, last_name = {last_name}')
print(f'Привет, {first_name}!')
hello_user('Роман', 'Пупкин')
#first_name = Роман, last_name = Пупкин
#Привет, Роман!
В функцию hello_user
, мы добавили параметр log
, который по умолчанию равен True
.
Далее в теле функции мы добавили условие, если log
равен True
, то выводим информацию о том, что присвоено каждой переменной print(f'first_name = {first_name}, last_name = {last_name}')
.
И так как, значение log
у нас по умолчанию True
, то мы видим first_name = Роман, last_name = Пупкин
.
А теперь давайте при вызове функции изменим значение этого параметра по умолчанию:
def hello_user(first_name, last_name, log=True):
if log:
print(f'first_name = {first_name}, last_name = {last_name}')
print(f'Привет, {first_name}!')
hello_user('Роман', 'Пупкин', False)
#Привет, Роман!
Теперь мы видим только приветствие, т.к. условие if log
вернуло результат False
и блок с условием не вывелся.
Мы также могли бы передать третий параметр и как именованный аргумент, все отработает точно так же:
def hello_user(first_name, last_name, log=True):
if log:
print(f'first_name = {first_name}, last_name = {last_name}')
print(f'Привет, {first_name}!')
hello_user('Роман', 'Пупкин', log=False)
#Привет, Роман!
Параметры функции, которые идут сразу со значениями по умолчанию называют формальными параметрами.
А те, параметры, которые не имеют значений по умолчанию — фактическими параметрами.
Если заранее неизвестно количество аргументов, которые будут переданы в функцию — можно воспользоваться аргументами переменной длины.
Для того, чтобы передать в функцию произвольное число позиционных аргументов, перед именем параметра, который будет их принимать нужно поставить знак *
:
def my_function(*args):
print(args)
my_function(1, 2, 3, 4)
#(1, 2, 3, 4)
Передаем в функцию любое количество позиционных аргументов и на выходе получаем кортеж из этих аргументов.
Но если нужно передавать в функцию и позиционные элементы (количество которых известно), и произвольное число аргументов, то сначала следует вводить позиционные, а потом произвольные:
def my_function(a, b, *args):
print(a, b, args)
my_function(1, 2, 3, 4)
#1 2 (3, 4)
Если сделать наоборот, то будет ошибка:
def my_function(*args, a, b):
print(a, b, args)
my_function(1, 2, 3, 4)
#TypeError: my_function() missing 2 required keyword-only arguments: 'a' and 'b'
Для того, чтобы передать в функцию переменное число именованных аргументов (т.е. пар ‘ключ=значение’), перед именем параметра нужно поставить **
:
def my_function(**kwargs):
print(kwargs)
my_function(a=1, b=2, c=3, d=4)
#{'a': 1, 'b': 2, 'c': 3, 'd': 4}
В результате получаем словарь из введенных в функцию аргументов.
Теперь давайте соберем все возможные аргументы, которые мы рассмотрели выше:
def my_function(a, b, *args, c=0, d=0, **kwargs):
print(a, b, args, c, d, kwargs)
my_function(1, 2, 3, 4, 5, e=6, f=7)
#1 2 (3, 4, 5) 0 0 {'e': 6, 'f': 7}
Именно в таком порядке нужно указывать параметры в функции:
Рекурсивная функция — это функция, которая вызывает сама себя.
С помощью рекурсивной функции выведем числ от 1 до n:
def rec_n(n):
if n > 1:
rec_n(n - 1)
print(n)
rec_n(5)
#1
#2
#3
#4
#5
Тема рекурсии не проста и я лучше сделаю отдельный пост о том, как это работает, чтобы не растягавать этот пост, который посвящен функциям в целом)
Lambda функции — анонимные функции, которые не имеют имени и записываются в одну строку.
Синтаксис lambda функции
lambda <аргумент(ы)>: <выражение>
Эти функции могут иметь неограниченное количество аргументов, а также могут и вовсе не иметь ни одного аргумента. Но они обязательно имеют только одно выражение.
Без аргументов:
a = lambda: 'Просто строка'
print(a())
#Просто строка
С одним аргументом:
a = lambda x: x ** 2
print(a(2))
#4
С несколькими аргументами:
a = lambda x, y: x + y
print(a(1, 2))
#3
А вот также самая функция записанная классическим способом:
def func(x, y):
return x + y
print(func(1, 2))
#3
Также в lambda функциях можно использовать тренарный оператор:
[если истина] if [выражение] else [если ложь]
a = lambda x: True if x > 0 else False
print(a(-9))
#False
Здесь мы передаем в анонимную функцию аргумент и если он больше 0, то возвращаем True
, а иначе False
.
Область видимости отвечает за то, какие переменные и в каких частях программы нам видно и мы можем использовать, а в каких они скрыты.
В Python существует 3 области видимости:
Локальная переменная находится внутри функции.
Создадим простую функцию и вызовем ее:
def my_sum(a, b):
s = a + b
print(s)
my_sum(1, 2)
#3
В этой функции переменная s
является локальной переменной. Это значит, что сама переменная s существует только внутри нашей созданной функции. И если мы попытаемся обратиться к этой переменной за пределом функции, то получим ошибку:
def my_sum(a, b):
s = a + b
print(s)
my_sum(1, 2)
print(s)
#3
#NameError: name 's' is not defined
Т.е. так как переменная s
является локальной, то Python нам говорит, что переменная неопределена.
Глобальные переменные определяются на уровне основной программы и доступны в любом месте этой программы, включая функции.
x = 100
def my_sum(a, b):
s = a + b + x
print(s)
my_sum(1, 2)
#103
Мы добавили переменную x и обратились к ней в функции, в результате все отработало, как надо и мы получили нужный результат.
Что будет, если внутри функции изменить значение глобальной переменной?
x = 100
def my_sum(a, b):
x = 0
s = a + b + x
print(s)
my_sum(1, 2)
print(x)
#3
#100
Глобальная переменная x = 100
, внутри функции, мы присвоили переменной x = 0
, в итоге функции отработала ожидаемо 1 + 2 + 0 = 3, но print(x)
все равно показал значение x = 100
.
Все дело в том, что внутри функции была создана новая переменная, с таким же названием, как и глобальная переменная, но с другим значением, а сама глобальная переменная не была изменена.
Если же нам нужно работать именно с глобальной переменной, то нужно прописать ключевое слово global
:
x = 100
def my_sum(a, b):
global x
x = 0
s = a + b + x
print(s)
my_sum(1, 2)
print(x)
#3
#0
В этом случае после того, как мы написали global x
, мы начали работать внутри функции именно с глобальной переменной x
, присвоили ей значение 0 и print(x)
показал значение x = 0
.
Как работают нелокальные переменные наглядно можно увидеть на примере вложенных функций:
x = 0
def func_1():
x = 1
def func_2():
x = 2
print('func_2 x =', x)
func_2()
print('func_1 x =', x)
func_1()
print('global x =', x)
#func_2 x = 2
#func_1 x = 1
#global x = 0
Здесь мы создали глобальную переменную x = 0
, функцию func_1()
в которой x = 1
и вложенную функцию func_2()
в которой x = 2
. В обеих функциях прописали print()
для вывода их локальных переменных x
и вызвали вложенную функцию func_2()
из функции func_1()
.
А в конце просто вызвали функцию func_1()
и print(x)
для отображения глобальной переменной.
В итоге мы увидели в консоли, что все верно и каждая функция имеет свою локальную переменную с одним и тем же именем, что и глобальная переменная, но значения у всех переменных свое, которое зависит от области видимости.
Для того, чтобы работать из вложенной функции с переменной из ее родительской функции необходимо использовать ключевое слово nonlocal
:
x = 0
def func_1():
x = 1
def func_2():
nonlocal x
x = 2
print('func_2 x =', x)
func_2()
print('func_1 x =', x)
func_1()
print('global x =', x)
#func_2 x = 2
#func_1 x = 2
#global x = 0
Таким образом, с помощью nonlocal
мы работаем напрямую с переменной из родительской функции, изменяя эту переменную внутри вложенной функции, эта переменная меняется и в родительской функции.
Но если мы напишем nonlocal
в родительской функции, то получим ошибку:
x = 0
def func_1():
nonlocal x
x = 1
def func_2():
x = 2
print('func_2 x =', x)
func_2()
print('func_1 x =', x)
func_1()
print('global x =', x)
#Syntax Error: no binding for nonlocal 'x' found
Это говорит, что внешняя область видимости родительской функции func_1()
является глобальным, а nonlocal
можно использовать только в локальной области видимости.
Здесь уже нужно использовать global
:
x = 0
def func_1():
global x
x = 1
def func_2():
x = 2
print('func_2 x =', x)
func_2()
print('func_1 x =', x)
func_1()
print('global x =', x)
#func_2 x = 2
#func_1 x = 1
#global x = 1
Содержание: