Функции

Программа робота получает данные, проверяет условия и выдаёт команды. Если весь алгоритм записан одним длинным блоком, через несколько десятков строк становится трудно понять, где измеряется расстояние, где принимается решение, а где задаётся скорость моторов. Функции позволяют дать каждому законченному действию имя и вызывать его тогда, когда оно нужно.
Функция — именованный блок кода, который можно вызывать многократно. Она может получать входные значения через параметры, выполнять действия и возвращать результат оператором return.
Зачем это нужно
Допустим, показание дальномера нужно переводить из миллиметров в сантиметры в трёх местах программы. Если трижды написать одну формулу, любое исправление придётся повторять трижды. Расхождение хотя бы в одной копии даст разные результаты для одинакового сигнала.
Можно один раз определить действие millimeters_to_centimeters, а затем вызывать его с разными измерениями:
def millimeters_to_centimeters(distance_mm):
return distance_mm / 10
front_cm = millimeters_to_centimeters(275)
left_cm = millimeters_to_centimeters(430)
right_cm = millimeters_to_centimeters(190)
Имя функции объясняет назначение вычисления. Формула хранится в одном месте, а каждый вызов передаёт своё значение. Кроме повторного использования, это даёт ещё одно преимущество: небольшую функцию проще проверить отдельно от драйвера датчика и управления двигателями.
Главная идея
Функцию удобно представлять как модуль с контрактом:
аргументы -> функция -> возвращаемый результат
В определении указывают имя и параметры:
def clamp_speed(speed, minimum, maximum):
if speed < minimum:
return minimum
if speed > maximum:
return maximum
return speed
Вызов передаёт конкретные аргументы:
safe_speed = clamp_speed(72, 0, 60)
print(safe_speed) # 60
Здесь speed, minimum и maximum — параметры определения. Числа 72, 0 и 60 — аргументы вызова. После return функция завершается, а значение 60 становится результатом выражения clamp_speed(...).
| Часть | Роль | Пример |
|---|---|---|
def | Начинает определение функции | def clamp_speed(...): |
| Имя | Обозначает действие | clamp_speed |
| Параметры | Принимают входные значения | speed, minimum, maximum |
| Тело | Выполняет вычисления и команды | проверки if |
return | Завершает вызов и передаёт результат | return maximum |
| Вызов | Запускает тело с аргументами | clamp_speed(72, 0, 60) |
Определение и вызов
После строки def ставятся круглые скобки, двоеточие и блок с отступом. Само определение не выполняет тело как обычную команду движения: оно создаёт объект функции и связывает его с именем. Тело запускается при вызове.
def signal_ready():
print("Система готова")
signal_ready()
signal_ready()
Пустые скобки означают, что функция не требует аргументов. Два вызова выполнят одно действие два раза.
Функцию обычно определяют до того места, где её вызывают во время исполнения. В небольшом скрипте определения часто размещают сверху, а запуск сценария — снизу:
def read_simulated_sensor():
return 245
distance_mm = read_simulated_sensor()
print(distance_mm)
Пустые строки между верхнеуровневыми функциями и остальным кодом не меняют вычисления, но делают структуру файла заметнее.
Параметры и аргументы
Параметр получает ссылку на объект, переданный при вызове. Один и тот же алгоритм поэтому работает с разными входами:
def is_obstacle_close(distance_mm, limit_mm):
return distance_mm <= limit_mm
front_alert = is_obstacle_close(115, 120)
side_alert = is_obstacle_close(180, 100)
print(front_alert) # True
print(side_alert) # False
Число и порядок аргументов должны соответствовать параметрам, если не используются значения по умолчанию или именованные аргументы. Понятные имена помогают не перепутать физические величины. Суффикс _mm показывает единицу измерения, а _percent — условный процент мощности.
Аргументы можно указывать по позиции или по имени:
def motor_command(left_percent, right_percent):
return left_percent, right_percent
straight = motor_command(40, 40)
turn_left = motor_command(left_percent=15, right_percent=45)
print(straight)
print(turn_left)
Именованный вызов длиннее, зато сразу показывает, какое значение относится к левому и правому мотору. Позиционные аргументы нельзя помещать после именованных в одном вызове.
Значения параметров по умолчанию
Параметру можно назначить значение по умолчанию. Тогда вызывающий код вправе его не передавать:
def corrected_distance(raw_mm, offset_mm=0):
return raw_mm + offset_mm
plain = corrected_distance(250)
calibrated = corrected_distance(250, offset_mm=-8)
print(plain) # 250
print(calibrated) # 242
Параметры без значения по умолчанию должны находиться перед параметрами с ним. Выражение для значения по умолчанию вычисляется один раз — в момент выполнения определения функции. Поэтому изменяемый список в роли значения по умолчанию может неожиданно сохранять данные между вызовами.
Так писать не стоит:
def remember_measurement(value, history=[]):
history.append(value)
return history
Безопаснее использовать None как метку «список не передан»:
def remember_measurement(value, history=None):
if history is None:
history = []
history.append(value)
return history
Этот приём создаёт новый список для каждого вызова без аргумента history. Если готовый список передан явно, функция добавляет значение именно в него — это уже часть её контракта.
Что возвращает функция
return может возвращать число, строку, логическое значение, список или другой объект. Несколько результатов часто собирают в кортеж:
def wheel_speeds(base_speed, correction):
left = base_speed - correction
right = base_speed + correction
return left, right
left_speed, right_speed = wheel_speeds(40, 8)
print(left_speed, right_speed) # 32 48
Если функция достигает конца без return, результатом становится None. То же происходит при return без значения:
def print_status(message):
print(message)
result = print_status("Старт")
print(result) # None
Функция вывела текст как побочный эффект, но не вычислила полезный результат. Смешивать вывод и вычисление не всегда ошибка, однако функцию, которая возвращает значение, легче применять повторно: вызывающий код сам решит, вывести его, сохранить в файл или передать дальше.
print и return — разные действияprint показывает значение в консоли. return передаёт значение из функции в место вызова. Напечатанное значение не становится автоматически результатом функции.
Локальные имена и область видимости
Параметры и имена, созданные внутри функции, обычно локальны. Они существуют для конкретного вызова и не доступны по имени снаружи:
def average_distance(readings_mm):
total = sum(readings_mm)
return total / len(readings_mm)
average = average_distance([220, 210, 205])
print(average)
Имя total относится к локальной области функции. Это уменьшает случайное влияние одной части программы на другую. Глобальные константы могут быть полезны, но изменяемое глобальное состояние усложняет проверку: результат начинает зависеть не только от аргументов.
Хороший учебный ориентир — передавать необходимые данные параметрами и возвращать результат. Например, порог можно сделать аргументом, а не скрыто читать из глобальной переменной.
Функции как этапы управления

Алгоритм робота удобно разделить на три этапа:
- подготовить показание датчика;
- выбрать режим движения;
- сформировать команды левому и правому мотору.
def normalize_distance(raw_mm, offset_mm=0):
corrected = raw_mm + offset_mm
return max(0, corrected)
def choose_motion(distance_mm, stop_mm=120, slow_mm=300):
if distance_mm <= stop_mm:
return "stop"
if distance_mm <= slow_mm:
return "slow"
return "forward"
def speeds_for_motion(motion):
if motion == "stop":
return 0, 0
if motion == "slow":
return 25, 25
return 50, 50
raw_distance_mm = 268
distance_mm = normalize_distance(raw_distance_mm, offset_mm=-6)
motion = choose_motion(distance_mm)
left_speed, right_speed = speeds_for_motion(motion)
print(distance_mm, motion, left_speed, right_speed)
Каждая функция решает одну задачу и имеет наблюдаемый результат. Для проверки choose_motion не нужен настоящий дальномер: достаточно передать заранее выбранные расстояния. Для проверки speeds_for_motion не нужны моторы: можно сравнить возвращённую пару с ожидаемой командой.
В реальном проекте отдельная функция или объект драйвера применит скорости к выводам контроллера. Такое разделение удерживает аппаратно-зависимый код на границе программы и оставляет расчёты проверяемыми на обычном компьютере.
Документация и аннотации типов
Короткая строка документации объясняет контракт функции. Аннотации подсказывают ожидаемые типы редактору и читателю:
def limit_percent(value: float, maximum: float = 100.0) -> float:
"""Ограничить неотрицательную команду заданным максимумом."""
return max(0.0, min(value, maximum))
Аннотации float и -> float не превращают Python в язык со строгой автоматической проверкой типов во время обычного вызова. Это метаданные: их используют документация, редакторы и отдельные инструменты анализа. Сам код всё равно должен корректно обрабатывать допустимые входы.
| Признак удачной функции | Зачем он нужен |
|---|---|
| Имя описывает действие | Вызов читается как часть алгоритма |
| Одна ясная задача | Проще проверить и изменить |
| Явные параметры | Видны входные зависимости |
| Предсказуемый результат | Функции легче соединять |
| Короткий контракт | Понятны единицы, допустимые значения и эффект |
| Аппаратные эффекты отделены от расчётов | Логику можно тестировать без робота |
Что запомнить о функциях
Определение через def создаёт функцию, вызов выполняет её тело, параметры принимают аргументы, а return завершает текущий вызов и передаёт результат. Значения по умолчанию делают часть аргументов необязательной, но изменяемые объекты нельзя бездумно использовать как такие значения. Локальные имена помогают изолировать вычисление, а небольшие функции превращают длинную программу в цепочку проверяемых действий.
Практика
Задание 1. Перевод единиц
Напишите функцию, которая получает расстояние в сантиметрах и возвращает миллиметры. Подберите несколько входных значений, включая ноль и дробное число.
Задание 2. Безопасная скорость
Создайте функцию ограничения команды мотора диапазоном от минимального до максимального значения. Границы передавай параметрами. Проверьте значение ниже диапазона, внутри него и выше него.
Задание 3. Решение по двум датчикам
Функция должна получать расстояния слева и справа и возвращать строковую команду для поворота или прямого движения. Самостоятельно сформулируйте правила и граничные случаи.
Задание 4. Именованные аргументы
Создайте функцию настройки движения с обязательной скоростью и необязательными порогами остановки и замедления. Сделайте несколько вызовов, используя именованные аргументы в разном порядке.
Задание 5. Разделение алгоритма
Возьмите программу, которая читает список показаний, вычисляет среднее и выбирает команду. Разделите её минимум на две функции так, чтобы расчёт можно было проверить без датчика и моторов.
Задание 6. Контракт
Добавьте к одной из функций строку документации и аннотации типов. В тексте контракта укажите единицы измерения и смысл возвращаемого результата.
Проверьте себя
- Чем определение функции отличается от вызова?
- В чём разница между параметром и аргументом?
- Что происходит после выполнения
return? - Какой результат даёт функция без
return? - Зачем нужны именованные аргументы?
- Почему изменяемый список опасен как значение параметра по умолчанию?
- Где доступно локальное имя функции?
- Проверяет ли обычный Python аннотации типов автоматически при каждом вызове?
Сначала ответьте без подсказки. Ответ можно считать полным, если вы:
- формулируете основную мысль своими словами;
- называете важные условия, ограничения или меры безопасности;
- для схемы, кода или расчёта показываете ход решения и ожидаемый результат.
Если один из пунктов объяснить не получается, найдите соответствующую главу статьи, перечитайте её и повторите ответ.
Словарь статьи
- Функция — вызываемый именованный блок кода.
- Определение функции — конструкция
def, которая создаёт функцию. - Вызов — выражение, запускающее тело функции.
- Параметр — имя входного значения в определении функции.
- Аргумент — конкретное значение, переданное при вызове.
- Возвращаемое значение — результат, который функция передаёт оператором
return. - Значение по умолчанию — значение параметра, используемое при отсутствии соответствующего аргумента.
- Именованный аргумент — аргумент, связанный с параметром по имени.
- Область видимости — часть программы, где имя доступно.
- Аннотация типа — метаданные об ожидаемом типе параметра или результата.
- Побочный эффект — изменение внешнего состояния, например вывод текста или команда мотору.
Связанные темы
- Переменные и типы данных — какие объекты получают параметры и возвращают функции.
- Условия — как функция выбирает один из нескольких результатов.
- Классы — как объединять данные и функции одного объекта.
- Работа с файлами — как вынести чтение и запись в отдельные операции.
- Библиотеки и виртуальные окружения — как функции объединяются в модули и пакеты.