Урок 22 Функции

def, return, параметры, аргументы

⏱ ~12 мин чтения· 📘 Базовый

Определение функции

Функция — это именованный блок кода, который можно вызывать:

def greet():
    print("Привет!")

greet()  # Вызов функции -> "Привет!"

Параметры и аргументы

Функции могут принимать входные данные:

def greet(name):
    print(f"Привет, {name}!")

greet("Анна")  # "Привет, Анна!"
greet("Мир")   # "Привет, Мир!"

Возврат значения — return

return передаёт результат обратно в вызывающий код:

def add(a, b):
    return a + b

result = add(5, 3)
print(result)  # 8

# Функция без return возвращает None
def do_nothing():
    pass

print(do_nothing())  # None

Параметры по умолчанию

Можно задать значения по умолчанию. Параметры со значениями по умолчанию всегда идут в конце списка — после обычных (обязательных) параметров:

def greet(name, greeting="Привет"):
    print(f"{greeting}, {name}!")

greet("Анна")           # "Привет, Анна!"
greet("Анна", "Здравствуйте")  # "Здравствуйте, Анна!"

Если расположить параметр со значением по умолчанию перед обязательным, Python вызовет ошибку SyntaxError.

Документирование (docstring)

Строка документации сразу после def:

def add(a, b):
    """Возвращает сумму двух чисел."""
    return a + b

print(add.__doc__)  # "Возвращает сумму двух чисел."
help(add)           # Покажет документацию

Несколько параметров

Функция может принимать любое количество параметров через запятую:

def describe_person(name, age, city):
    print(f"{name}, {age} лет, город {city}")

describe_person("Олег", 25, "Москва")
# "Олег, 25 лет, город Москва"

# Параметры передаются по порядку
def power(base, exp):
    return base ** exp

print(power(2, 10))   # 1024
print(power(10, 2))   # 100  (порядок важен!)

Область видимости переменных

Переменные, созданные внутри функции, не видны снаружи (локальная область видимости):

def my_func():
    x = 100        # Локальная переменная
    print(x)

my_func()          # 100
# print(x)         # Ошибка! NameError: x не определена

Глобальные переменные и global

Значение глобальной переменной (созданной вне функции) можно свободно читать внутри функции. Но если присвоить ей новое значение, Python создаст новую локальную переменную с тем же именем — глобальная не изменится:

count = 10

def set_count():
    count = 5        # Локальная переменная, не глобальная!

set_count()
print(count)         # 10 (глобальная не изменилась)

Чтобы изменить именно глобальную переменную, используйте оператор global внутри функции:

count = 10

def set_count():
    global count     # Обращаемся к глобальной переменной
    count = 5

set_count()
print(count)         # 5 (теперь изменилась!)

global указывается в начале функции, до присваивания. Используйте его осторожно: злоупотребление глобальными переменными усложняет отладку. Лучше передавать значения через параметры и возвращать результат через return.

Именованные аргументы

При вызове можно явно указать, какому параметру присваивается значение. Это позволяет не запоминать порядок:

def greet(name, greeting="Привет"):
    print(f"{greeting}, {name}!")

# Позиционные аргументы (по порядку)
greet("Анна", "Здравствуйте")     # "Здравствуйте, Анна!"

# Именованные аргументы (порядок не важен)
greet(greeting="Здравствуйте", name="Анна")  # "Здравствуйте, Анна!"
greet(name="Борис")                          # "Привет, Борис!"

# Смешанный вызов: сначала позиционные, затем именованные
greet("Виктор", greeting="Добрый день")      # "Добрый день, Виктор!"

Аннотации типов

Начиная с Python 3.5 (PEP 484), можно указывать ожидаемые типы параметров и возвращаемого значения, а с Python 3.6 (PEP 526) — аннотации переменных. Это помогает читать код и использовать автодополнение в IDE:

def add(a: int, b: int) -> int:
    """Складывает два целых числа."""
    return a + b

def greet(name: str, times: int = 1) -> None:
    """Приветствует указанное количество раз."""
    for _ in range(times):
        print(f"Привет, {name}!")

result: int = add(5, 3)   # Аннотация переменной
greet("Анна", 3)           # Аннотации не проверяются во время выполнения

⚠️ Важно: аннотации типов не проверяются интерпретатором. Для проверки используйте инструменты вроде mypy.

def add(a: int, b: int) -> int:
    return a + b

# Интерпретатор не проверяет типы — это просто подсказки
print(add(2, 3))        # 5
print(add("a", "b"))    # "ab" — хотя ожидались числа, ошибки нет

Практический пример: калькулятор

Объединим изученные концепции в одной программе:

def calculate(a: float, b: float, operation: str = "+") -> float:
    """Выполняет арифметическую операцию над двумя числами.

    Аргументы:
        a, b — числа
        operation — знак операции: "+", "-", "*", "/"

    Возвращает:
        Результат вычисления.
    """
    if operation == "+":
        return a + b
    elif operation == "-":
        return a - b
    elif operation == "*":
        return a * b
    elif operation == "/":
        if b != 0:
            return a / b
        else:
            print("Ошибка: деление на ноль!")
            return None
    else:
        print(f"Неизвестная операция: {operation}")
        return None

# Использование
print(calculate(10, 5, "+"))   # 15  (аннотации не конвертируют типы — 10 + 5 = 15)
print(calculate(10, 5, "/"))   # 2.0 (деление всегда возвращает float)
print(calculate(10, 0, "/"))   # Ошибка: деление на ноль!
                               # None