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

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

Ключевые вопросы статьи

  • Как создавать собственные функции и зачем они нужны?
  • Что такое аргументы функции и как они передаются?
  • Как работает оператор return и какие значения может возвращать функция?
  • Что такое область видимости? Чем различаются локальные и глобальные переменные?
  • Как безопасно изменять переменные, переданные в функцию?

Как создавать собственные функции и зачем они нужны

Вы уже познакомились с некоторыми встроенными функциями Python — например, print(), input(), max(), min() и другими.

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

Функции позволяют:

  • переиспользовать один и тот же код без копирования;
  • сделать программу более читаемой и структурированной — за счёт разделения логики на небольшие, понятные блоки.

Синтаксис функции

Вот как выглядит базовое определение функции в Python:

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. Как только срабатывает первый из них, выполнение функции немедленно прекращается, а результат передаётся в основную программу.

Пример: перепишем функцию only_even так, чтобы сразу возвращать результат без использования флага 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

Если в функции отсутствует return или он используется без значения, Python всё равно вернёт специальный объект None. Это тип, обозначающий отсутствие результата.

Пример:

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

# Вывод программы:
# Эту строку выведет функция до возврата значения.
# None

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

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)

Примечание

В первом случае функция возвращает значение логического типа (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

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

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

Пример:

def check_password(pwd):
    return pwd == password

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

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

В этом случае переменная password определена глобально и доступна внутри функции check_password.

Важно

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

Как безопасно изменять переменные, переданные в функцию

Можно ли изменить переменную из глобальной области видимости внутри функции? Ответ зависит от типа данных переменной:

  • Если это изменяемый тип (например, список), то изменение происходит напрямую.
  • Если это неизменяемый тип (например, число или строка), то попытка изменить значение создаёт локальную копию с тем же именем.

Рассмотрим пример с изменяемым типом — списком:

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]

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

То же самое касается аргументов функции. Они ведут себя как локальные переменные:

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.

Однако использовать global нужно с осторожностью. Глобальные переменные делают код менее предсказуемым: любое изменение может произойти в любой части программы, и это затрудняет отладку.

Обычно лучше передавать значения в функцию и возвращать результат, как показано ниже:

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.

Что дальше

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

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

Дальше вас ждёт следующий шаг — гибкие способы передачи аргументов и работа с функциями как объектами. Мы поговорим про позиционные и именованные аргументы, значения по умолчанию, а также научимся передавать в функции другие функции. Вы узнаете, что такое *args, **kwargs, как устроены функции высшего порядка и зачем нужны лямбда-выражения.

Ключевые выводы статьи

  • Функции позволяют переиспользовать код, делить программу на логические блоки и повышать читаемость.
  • Аргументы функции — это переменные, значения которых передаются при вызове и доступны только внутри функции (локальная область видимости).
  • Оператор return завершает выполнение функции и возвращает результат. Если return не указан, функция возвращает None.
  • Функция может возвращать сразу несколько значений — в этом случае они автоматически упаковываются в кортеж.
  • Локальные и глобальные переменные различаются по области действия: локальные живут только внутри функции, а глобальные доступны во всей программе. Изменять глобальные переменные внутри функции стоит только при необходимости: обычно лучше передавать значения через аргументы и возвращать результат.