4.1. Функции. Области видимости. Передача параметров в функции

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

В процессе нашего обучения мы изучили ряд встроенных в Python функций: print(), input(), max(), min() и др. Часто в программах требуется использовать какую-то часть кода несколько раз. В таком случае программисты создают функции. Функции помогают использовать написанный код в программах многократно, а также делают его более понятным за счёт деления на блоки.

Синтаксис создания функции выглядит следующим образом:

1def <имя функции>(<аргументы функции>):
2    <тело функции>

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

Напишем функцию, которая проверяет, что список целых чисел, передаваемый ей как аргумент, содержит только чётные числа:

1def only_even(numbers):
2    result = True
3    for x in numbers:
4        if x % 2 != 0:
5            result = False
6            break
7    return result
8
9
10print(only_even([2, 4, 6]))
11print(only_even([1, 2, 3]))

Вывод программы:

True
False

В функциях можно использовать несколько операторов return. Первый сработавший в теле функции оператор return остановит выполнение функции и вернёт её значение. Наш пример можно упростить, использовав вместо флага result несколько точек возврата значения:

1def only_even(numbers):
2    for x in numbers:
3        if x % 2 != 0:
4            return False
5    return True
6
7
8print(only_even([2, 4, 6]))
9print(only_even([1, 2, 3]))

Вывод программы:

True
False

Обратите внимание: функция в Python всегда возвращает результат, даже если в ней нет return или присутствует return без возвращаемого значения. Тогда возвращаемый результат будет None — специальный тип данных в Python, который дословно можно перевести с английского как «ничего». Например, None возвращает функция print():

1print(print("Эту строку выведет функция до возврата значения."))

Вывод программы:

Эту строку выведет функция до возврата значения.
None

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

1def only_even(numbers):
2    for i, x in enumerate(numbers):
3        if x % 2 != 0:
4            return False, i
5    return True
6
7
8print(only_even([2, 4, 6]))
9print(only_even([1, 2, 3]))

Вывод программы:

True
(False, 0)

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

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

1def only_even(numbers):
2    for i, x in enumerate(numbers):
3        if x % 2 != 0:
4            return False, i
5    return True
6
7
8print(numbers)

Вывод программы:

NameError: name 'numbers' is not defined

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

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

1def check_password(pwd):
2    return pwd == password
3
4
5password = "Python"
6print(check_password("123"))

Вывод программы:

False

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

1def list_modify():
2    del sample[-1]
3
4
5sample = [1, 2, 3]
6list_modify()
7print(sample)

Вывод программы:

[1, 2]

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

1def list_modify():
2    sample = [4, 5, 6]
3
4
5sample = [1, 2, 3]
6list_modify()
7print(sample)

Вывод программы:

[1, 2, 3]

Мы уже знаем, что аргумент функции — это локальная переменная. К нему также относится правило: изменение значения переменной (если это разрешено типом данных) действует на внешнюю переменную, а присваивание нового значения создаёт локальную переменную функции:

1def list_modify_1(list_arg):
2    # создаём новый локальный список, не имеющий связи с внешним
3    list_arg = [1, 2, 3, 4]
4
5
6def list_modify_2(list_arg):
7    # меняем исходный внешний список, переданный как аргумент
8    list_arg += [4]
9
10
11sample_1 = [1, 2, 3]
12sample_2 = [1, 2, 3]
13list_modify_1(sample_1)
14list_modify_2(sample_2)
15print(sample_1)
16print(sample_2)

Вывод программы:

[1, 2, 3]
[1, 2, 3, 4]

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

1def inc():
2    global x
3    x += 1
4    print(f"Количество вызовов функции равно {x}.")
5
6
7x = 0
8inc()
9inc()
10inc()

Вывод программы:

Количество вызовов функции равно 1.
Количество вызовов функции равно 2.
Количество вызовов функции равно 3.

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

1def f(count):
2    count += 1
3    print(f'Количество вызовов функции равно {count}.')
4    return count
5
6    
7count_f = 0
8count_f = f(count_f)
9count_f = f(count_f)
10count_f = f(count_f)

Вывод программы:

Количество вызовов функции равно 1.
Количество вызовов функции равно 2.
Количество вызовов функции равно 3.

Отмечайте параграфы как прочитанные чтобы видеть свой прогресс обучения

Вступайте в сообщество хендбука

Здесь можно найти единомышленников, экспертов и просто интересных собеседников. А ещё — получить помощь или поделиться знаниями.
Вступить
Сообщить об ошибке
Предыдущий параграф3.5. Потоковый ввод/вывод. Работа с текстовыми файлами. JSON

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

Следующий параграф4.2. Позиционные и именованные аргументы. Функции высших порядков. Лямбда-функции

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

Функции на максималках

Лямбда-функции отлично подходят для компактных вычислений, а их потенциал можно раскрыть ещё больше, развернув их в облаке. С помощью Yandex Cloud Functions функции становятся доступными из любого места, позволяя автоматизировать обработку данных, создавать API и реализовывать масштабируемые решения.