Основы программирования
Функции
**Загадка:** Есть код для расчёта скидки. Он нужен в 20 местах программы. Копировать 20 раз? А если нужно изменить формулу - менять в 20 местах? Функции решают эту проблему раз и навсегда.
Функция - это именованный блок кода, который можно вызывать сколько угодно раз. Встроенные функции print(), len(), range() работают по той же механике, а в этом уроке - создание собственных.
Цели урока
- Понять что такое функция и зачем она нужна
- Научиться создавать функции с параметрами
- Освоить возврат значений (return)
- Понять разницу между параметрами и аргументами
Предварительные знания
- Переменные и типы (урок 3)
- Условные операторы (урок 6)
- Циклы (урок 7)
Каждое приложение - это набор функций. Нажал кнопку "Купить"? Вызвалась функция process_payment(). Отправил сообщение? Функция send_message(). Функции - это кирпичики программ.
- **API**: каждый endpoint - это функция на сервере
- **Библиотеки**: pandas, numpy, requests - наборы функций
- **Игры**: move_player(), check_collision(), render_frame()
- **Бизнес**: calculate_tax(), send_invoice(), generate_report()
От лямбда-исчисления Чёрча до стрелочных функций JavaScript
Идея функции как объекта старше любого языка программирования. В 1936 году Алонзо Чёрч в Принстоне формализовал лямбда-исчисление: математическую модель вычислений, где всё построено на анонимных функциях и их применении. На той же конференции Алан Тьюринг (ученик Чёрча) показал, что лямбда-исчисление и машина Тьюринга равно мощны. На практике подпрограмма как переиспользуемый блок появилась в работах Грейс Хоппер в конце 1940-х на компьютере UNIVAC: она первой назвала библиотеку готовых блоков subroutines. В 1958 году Джон Маккарти в MIT создал Lisp, где функции стали first-class объектами: их можно передавать как аргументы, возвращать как результат, хранить в переменных. В 1972 году Деннис Ритчи в C добавил указатели на функции: первое практическое first-class из мейнстрима. В 1995 году Брендан Эйх за десять дней сделал JavaScript с функциями как объектами, что подготовило почву для функционального стиля в вебе. В 2015 году ES6 добавил стрелочные функции: const f = x => x * 2, лексический this, компактный синтаксис. Сегодня анонимные функции есть везде: lambda в Python, fn в Rust, замыкания в Kotlin и Swift. Идея Чёрча 1936 года теперь крутится в каждом браузере, на каждом сервере, в каждом приложении.
Создание функции: def
**def** (define) - ключевое слово для создания функции. После него - имя функции и круглые скобки.
Простейшая функция
Определение и вызов
```python # Определение функции def greet(): print("Привет!") print("Как дела?") # Вызов функции greet() # Привет! Как дела? greet() # Можно вызывать сколько угодно раз! ``` **Структура:** 1. `def` - ключевое слово 2. `greet` - имя функции (как переменная, snake_case) 3. `()` - скобки для параметров (пока пустые) 4. `:` - двоеточие в конце строки 5. Тело функции - с отступом
**Определение ≠ Выполнение!** Код внутри функции НЕ выполняется до явного вызова. `def greet():` просто создаёт функцию, а `greet()` - вызывает её.
Что произойдёт при выполнении кода? ```python def hello(): print("Hello") ```
Параметры: входные данные
**Параметры** - переменные в скобках при определении функции. Они получают значения при вызове.
Функция с параметром
Персонализированное приветствие
```python # name - параметр (placeholder) def greet(name): print(f"Привет, {name}!") # При вызове передаём аргумент greet("Алиса") # Привет, Алиса! greet("Боб") # Привет, Боб! # Несколько параметров def greet_full(first_name, last_name): print(f"Здравствуйте, {first_name} {last_name}!") greet_full("Иван", "Петров") # Здравствуйте, Иван Петров! ```
**Параметр vs Аргумент:** - **Параметр** - переменная в определении: `def greet(name)` - **Аргумент** - конкретное значение при вызове: `greet("Алиса")`
Функция-калькулятор
Расчёт с параметрами
```python def calculate_area(width, height): area = width * height print(f"Площадь: {area}") calculate_area(5, 3) # Площадь: 15 calculate_area(10, 2) # Площадь: 20 # Порядок аргументов важен! calculate_area(3, 5) # То же самое, но аргументы в другом порядке ```
Что выведет код? ```python def add(a, b): print(a + b) add(3, 5) ```
return: возврат результата
**return** - возвращает значение из функции. Функция превращается в "машину", которая принимает входные данные и выдаёт результат.
Функция с return
Вместо print - return
```python # Без return (только печатает) def add_print(a, b): print(a + b) # Просто выводит # С return (возвращает значение) def add(a, b): return a + b # Возвращает результат # Разница: add_print(3, 5) # Выведет 8, но результат "пропадёт" result = add(3, 5) # result = 8, можно использовать дальше! print(result * 2) # 16 total = add(add(1, 2), add(3, 4)) # 1+2 + 3+4 = 10 ```
**return прерывает функцию!** Код после return не выполнится. Это можно использовать для раннего выхода.
Ранний return
Выход при условии
```python def divide(a, b): if b == 0: return None # Ранний выход при ошибке return a / b print(divide(10, 2)) # 5.0 print(divide(10, 0)) # None (деление на 0) ```
print() и return - одно и то же
print() выводит на экран, return - возвращает значение для дальнейшего использования
print() - это побочный эффект (вывод). return - это результат функции, который можно сохранить в переменную, передать другой функции, использовать в вычислениях.
Что будет в x? ```python def mystery(n): return n * 2 print("Done") x = mystery(5) ```
Значения по умолчанию
Параметрам можно задать **значения по умолчанию**. Если аргумент не передан - используется default.
Параметры со значениями по умолчанию
Опциональные аргументы
```python def greet(name, greeting="Привет"): print(f"{greeting}, {name}!") greet("Алиса") # Привет, Алиса! greet("Боб", "Здравствуй") # Здравствуй, Боб! greet("Вика", greeting="Хай") # Хай, Вика! # Практический пример def power(base, exponent=2): return base ** exponent print(power(5)) # 25 (5²) print(power(5, 3)) # 125 (5³) ```
**Правило:** параметры со значениями по умолчанию должны идти ПОСЛЕ обычных параметров. `def f(a=1, b)` - ошибка!
Именованные аргументы
Явное указание параметра
```python def create_user(name, age, city="Неизвестно", active=True): print(f"{name}, {age} лет, {city}, активен: {active}") # Позиционные аргументы (по порядку) create_user("Алиса", 25, "Москва", False) # Именованные аргументы (в любом порядке) create_user(name="Боб", age=30, active=False) create_user("Вика", 28, active=False) # Смешанный вариант ```
Что выведет? ```python def f(a, b=10): return a + b print(f(5)) ```
Возврат нескольких значений
Python позволяет возвращать несколько значений через запятую. Технически это кортеж (tuple).
Множественный return
Несколько значений одновременно
```python def min_max(numbers): return min(numbers), max(numbers) # Распаковка результата minimum, maximum = min_max([3, 1, 4, 1, 5]) print(f"Min: {minimum}, Max: {maximum}") # Min: 1, Max: 5 # Или как кортеж result = min_max([3, 1, 4, 1, 5]) print(result) # (1, 5) # Практика: деление с остатком def divmod_custom(a, b): quotient = a // b remainder = a % b return quotient, remainder q, r = divmod_custom(17, 5) print(f"17 = 5 × {q} + {r}") # 17 = 5 × 3 + 2 ```
Что будет в a и b? ```python def swap(x, y): return y, x a, b = swap(1, 2) ```
Документирование функций
**Docstring** - строка документации в начале функции. Описывает что делает функция, какие параметры принимает, что возвращает.
Docstring в действии
Документируй свои функции
```python def calculate_bmi(weight, height): """ Вычисляет индекс массы тела (BMI). Args: weight: Вес в килограммах height: Рост в метрах Returns: BMI как float Example: >>> calculate_bmi(70, 1.75) 22.86 """ return weight / (height ** 2) # Доступ к документации print(calculate_bmi.__doc__) help(calculate_bmi) # Красивый вывод в консоли ```
В IDE (VS Code, PyCharm) docstring показывается при наведении на функцию. Пиши их для функций, которые будешь использовать повторно!
Где размещается docstring в функции?
Связь с другими темами
Функции лежат в основе почти всех абстракций программирования:
- Рекурсия — Функция вызывает саму себя, заменяя цикл явной декомпозицией задачи
- Область видимости — Параметры и локальные переменные живут в кадре стека функции
- Объекты — Методы это функции, привязанные к объекту через self
- Рефакторинг — Extract Function самый частый приём: разбить длинный код на маленькие функции
Итог
- def создаёт именованную функцию: имя, параметры, тело с отступом
- Параметры это переменные в определении, аргументы это конкретные значения при вызове
- return возвращает значение и немедленно завершает функцию, без return функция вернёт None
- Значения по умолчанию делают параметры опциональными, должны идти после обязательных
- Именованные аргументы (name=value) позволяют передавать параметры в любом порядке
- Чистая функция зависит только от своих аргументов и не имеет побочных эффектов: проще тестировать
Вопросы для размышления
- Как принцип единственной ответственности функции влияет на тестируемость кода?
- Чем чистая функция отличается от функции с побочными эффектами и почему это важно при рефакторинге?
- Какой размер функции считается оптимальным и почему слишком длинные функции сложнее поддерживать?
Связанные уроки
- prog-06-conditionals — Функции содержат ветвление чтобы менять поведение
- prog-10-scope — Каждый вызов функции создаёт свою область видимости
- prog-09-recursion — Рекурсия это функция вызывающая саму себя
- la-07-matrix-multiply — Функция отображает входы в выходы как преобразование
- mm-02-first-principles
- alg-01-big-o