Функции как объекты в Python — разбор примера с лямбдами
@python_quizРазберем этот квиз
Короткий и конкретный пример показывает важную особенность Python: функции — объекты первого класса. Разберём, как именно формируется результат и почему вывод программы — именно тот, который ожидается.
Исходный код

Пошаговый разбор
- make_ops принимает два аргумента — f и g — и возвращает список из трёх объектов:
- первый элемент — f (сама функция),
- второй — g (сама функция),
- третий — лямбда, которая при вызове применяет g к x, а затем f к результату (f(g(x))).
- add1 — функция, прибавляющая 1 к аргументу.
- mul2 — функция, умножающая аргумент на 2.
- В выражении [op(3) for op in make_ops(add1, mul2)] мы:
- получаем список функций/лямбды от make_ops,
- для каждой функции вызываем её с аргументом 3,
- собираем результаты в список.
Вычисления для каждого элемента:
- f(3) = add1(3) = 3 + 1 = 4
- g(3) = mul2(3) = 3 * 2 = 6
- лямбда: f(g(3)) = add1(mul2(3)) = add1(6) = 7
Итоговый вывод: [4, 6, 7]
Почему другие варианты неверны
- Вариант с третьим элементом 8 мог бы появиться, если бы лямбда вычисляла g(f(x)) (т.е. присваивала бы порядок вызова наоборот): mul2(add1(3)) = 2 * 4 = 8.
- Вариант с 5 был бы возможен, если бы третья функция делала что-то вроде f(f(3)) или возвращала фиксированное значение, но в данном коде этого не происходит.
- Вариант с 9 предполагает сумму или композицию, дающую 9; в текущей композиции f(g(3)) = 7, так что 9 — не результат.
Таким образом, правильный вывод — [4, 6, 7], потому что третья функция явно реализует композицию f(g(x)).
Небольшие замечания о замыканиях и поведении лямбд
- Лямбда внутри make_ops захватывает переменные f и g из окружения функции. Это обычное поведение замыканий: лямбда будет ссылаться на те объекты f и g, которые были переданы в make_ops.
- Важно помнить про «позднее связывание» (late binding) при создании лямбд в цикле: если лямбда ссылается на переменную цикла, все лямбды могут разделять последнее значение переменной. В данном примере такой проблемы нет, так как f и g — явные аргументы функции.
Пример проблемы позднего связывания и способа её избежать:

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

Здесь третья функция вычисляет mul2(add1(3)) = 8.
Вывод
Этот короткий пример — хорошая иллюстрация:
- функций как объектов первого класса,
- композиции функций и порядка вызова,
- замыканий в Python и возможных подводных камней (позднее связывание).
Понимание этих механизмов помогает предсказывать поведение кода и избегать ошибок при построении более сложных функциональных конструкций.