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

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

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

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

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

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

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

def only_even(numbers):
    result = True
    for x in numbers:
        if x % 2 != 0:
            result = False
            break
    return result


print(only_even([2, 4, 6]))
print(only_even([1, 2, 3]))

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

True
False

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

def only_even(numbers):
    for x in numbers:
        if x % 2 != 0:
            return False
    return True


print(only_even([2, 4, 6]))
print(only_even([1, 2, 3]))

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

True
False

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

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

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

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

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

def only_even(numbers):
    for i, x in enumerate(numbers):
        if x % 2 != 0:
            return False, i
    return True


print(only_even([2, 4, 6]))
print(only_even([1, 2, 3]))

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

True
(False, 0)

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

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

def only_even(numbers):
    for i, x in enumerate(numbers):
        if x % 2 != 0:
            return False, i
    return True


print(numbers)

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

NameError: name 'numbers' is not defined

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

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

def check_password(pwd):
    return pwd == password


password = "Python"
print(check_password("123"))

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

False

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

def list_modify():
    del sample[-1]


sample = [1, 2, 3]
list_modify()
print(sample)

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

[1, 2]

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

def list_modify():
    sample = [4, 5, 6]


sample = [1, 2, 3]
list_modify()
print(sample)

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

[1, 2, 3]

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

def list_modify_1(list_arg):
    # создаём новый локальный список, не имеющий связи с внешним
    list_arg = [1, 2, 3, 4]


def list_modify_2(list_arg):
    # меняем исходный внешний список, переданный как аргумент
    list_arg += [4]


sample_1 = [1, 2, 3]
sample_2 = [1, 2, 3]
list_modify_1(sample_1)
list_modify_2(sample_2)
print(sample_1)
print(sample_2)

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

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

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

def inc():
    global x
    x += 1
    print(f"Количество вызовов функции равно {x}.")


x = 0
inc()
inc()
inc()

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

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

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

def f(count):
    count += 1
    print(f'Количество вызовов функции равно {count}.')
    return count

    
count_f = 0
count_f = f(count_f)
count_f = f(count_f)
count_f = f(count_f)

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

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

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

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

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

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

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

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