← назад к разделу

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

def стоимость(цена, количество): return цена * количество 4990, 2 стоимостьцена × кол-во 9980 написали один раз — зовём отовсюду вход в тест, подготовка данных, своя проверка — всё это функции, которые перестают копироваться

Параметры входят, результат выходит через return. Меняется тело функции — меняется поведение во всех тестах сразу.

Как выглядит функция

живой пример

def поздороваться():
    print("Привет")

поздороваться()      # вызов: теперь напечатается
Запустить

Запуск примеров доступен в платном доступе. Там этот же код выполняется прямо в статье: редактор, запуск и проверка рядом с абзацем. Неделя бесплатно →

def — «определяю функцию», дальше имя, скобки и двоеточие. Тело — со сдвигом. Само определение ничего не делает: пока функцию не вызвали, внутри неё ничего не происходит.

Параметры: одно и то же, но с разными данными

живой пример

def поздороваться(имя):
    print(f"Привет, {имя}")

поздороваться("Анна")     # Привет, Анна
поздороваться("Иван")     # Привет, Иван
Запустить

Запуск примеров доступен в платном доступе. Там этот же код выполняется прямо в статье: редактор, запуск и проверка рядом с абзацем. Неделя бесплатно →

Имя в скобках — параметр: переменная, которая появится внутри функции с тем значением, которое передали при вызове.

Параметров может быть несколько:

живой пример

def стоимость(цена, количество):
    print(цена * количество)

стоимость(4990, 2)     # 9980
Запустить

Запуск примеров доступен в платном доступе. Там этот же код выполняется прямо в статье: редактор, запуск и проверка рядом с абзацем. Неделя бесплатно →

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

Печатать изнутри функции почти всегда неправильно: результат нужен не на экране, а в коде. Для этого return:

живой пример

def стоимость(цена, количество):
    return цена * количество

итого = стоимость(4990, 2)
print(итого)              # 9980
Запустить

Запуск примеров доступен в платном доступе. Там этот же код выполняется прямо в статье: редактор, запуск и проверка рядом с абзацем. Неделя бесплатно →

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

Функция может возвращать и ответ «да/нет» — такие особенно нужны в проверках:

живой пример

def оплачен(заказ):
    return заказ["status"] == "PAID"

заказ = {"id": "ord-042", "status": "PAID"}
if оплачен(заказ):
    print("заказ оплачен")
Запустить

Запуск примеров доступен в платном доступе. Там этот же код выполняется прямо в статье: редактор, запуск и проверка рядом с абзацем. Неделя бесплатно →

Значения по умолчанию

живой пример

def найти_заказы(заказы, статус="PAID"):
    return [з for з in заказы if з["status"] == статус]

заказы = [
    {"id": "ord-042", "status": "PAID", "total": 4990},
    {"id": "ord-043", "status": "CANCELLED", "total": 890},
    {"id": "ord-044", "status": "PAID", "total": 1780},
]

print(найти_заказы(заказы))                  # ищет PAID
print(найти_заказы(заказы, "CANCELLED"))     # ищет отменённые
Запустить

Запуск примеров доступен в платном доступе. Там этот же код выполняется прямо в статье: редактор, запуск и проверка рядом с абзацем. Неделя бесплатно →

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

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

живой пример

def плохо(элемент, куда=[]):     # так не делают
    куда.append(элемент)
    return куда
Запустить

Запуск примеров доступен в платном доступе. Там этот же код выполняется прямо в статье: редактор, запуск и проверка рядом с абзацем. Неделя бесплатно →

Такой список создаётся один раз на всю программу и копит значения между вызовами. Правильно — куда=None, а внутри if куда is None: куда = [].

Зачем это тестировщику

Три типичных применения, которые встретятся в первый же день.

Подготовка данных. Вход, токен, заголовки — в одну функцию:

живой пример

def войти(client):
    ответ = client.post("/auth/login", json={"email": "anna@example.com", "password": "secret123"})
    return {"Authorization": "Bearer " + ответ.json()["token"]}
Запустить

Запуск примеров доступен в платном доступе. Там этот же код выполняется прямо в статье: редактор, запуск и проверка рядом с абзацем. Неделя бесплатно →

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

Своя проверка. Условие, которое повторяется, выносят и называют по смыслу:

живой пример

def сумма_сходится(заказ):
    посчитано = sum(п["qty"] * п["price"] for п in заказ["items"])
    return посчитано == заказ["total"]

заказ = {"items": [{"qty": 1, "price": 4990}, {"qty": 2, "price": 890}], "total": 6770}
print(сумма_сходится(заказ))     # True
Запустить

Запуск примеров доступен в платном доступе. Там этот же код выполняется прямо в статье: редактор, запуск и проверка рядом с абзацем. Неделя бесплатно →

Читающий видит if not сумма_сходится(заказ) и понимает намерение без разбора арифметики.

Разбор ответа. Достать из вложенного ответа то, что нужно, — тоже функция: тест остаётся про проверку, а не про навигацию по словарям.

Как называть

Имя функции — глагол или вопрос: войти, найти_заказы, оплачен, сумма_сходится. В рабочем проекте пишут по-английски и в нижнем регистре через подчёркивание: login, find_orders, is_paid. Если имя получается длинным вроде сделать_всё_и_проверить — функция делает слишком много, её стоит разделить.

Что решать

Банк «Функции и проверки»:

Коротко

  • def имя(параметры): объявляет функцию; пока её не вызвали, внутри ничего не происходит.
  • return отдаёт результат наружу и заканчивает функцию; печатать изнутри — почти всегда ошибка.
  • Значение по умолчанию делает параметр необязательным; списком или словарём оно быть не должно.
  • В тестах функции закрывают три задачи: подготовка данных, своя проверка, разбор ответа.
  • Имя — глагол или вопрос; слишком длинное имя означает, что функция делает слишком много.

Что почитать дальше