Перейти к содержимому
На этой странице

Функции и их особенности

Все темы Python Developer

Какие способы существуют для определения функций в Python и в чем заключаются их различия?

Обычные функции в Python определяют с помощью def или lambda. Ниже также показано применение функций высшего порядка.

Определение функции с использованием ключевого слова def:

  • Этот способ наиболее распространен.

  • Функции, определенные с помощью def, могут иметь имя и список параметров.

  • Используются для определения пользовательских функций.

Пример:
def my_function(x):
    return x * 2

Лямбда-функции (анонимные функции):

  • Определяются с помощью ключевого слова lambda.

  • Обычно используются для создания простых однострочных функций.

  • Могут принимать любое количество аргументов, но содержат только одно выражение.

Пример:
multiply = lambda x: x * 2

Применение функций высшего порядка: map(), filter() и functools.reduce().

  • Функции высшего порядка принимают другие функции как аргументы или возвращают их. map() и filter() встроены, reduce() импортируется из functools.

  • Используются для выполнения операций над другими функциями или структурами данных.

Пример:
# Пример с map()
result = map(lambda x: x * 2, [1, 2, 3, 4])
print(list(result))  # Вывод: [2, 4, 6, 8]

Каким образом параметры передаются в функции Python?

Параметры в Python могут передаваться в функции двумя основными способами:

Позиционные параметры:

  • Параметры передаются в том порядке, в котором они определены в сигнатуре функции.

  • Позиционные параметры связываются с аргументами в вызове функции по их порядку.

  • Передаваемые значения связываются с параметрами согласно их позиции.

Пример:
def greet(name, age):
    print(f"Привет, {name}! Тебе {age} лет.")

greet("Иван", 30)  # Передача параметров по позиции

Именованные параметры:

  • Параметры передаются с указанием их имени в вызове функции.

  • Позволяют передавать параметры в любом порядке, если указаны их имена.

  • Улучшают читаемость кода и делают его более ясным.

Пример:
def greet(name, age):
    print(f"Привет, {name}! Тебе {age} лет.")

greet(age=30, name="Иван")  # Передача параметров по именам

Что такое лямбда-функции?

Это анонимные функции, которые могут быть определены без использования ключевого слова def. Они обычно используются для создания простых функций в одну строку кода, обычно для передачи встроенным функциям высшего порядка, таким как map(), filter() и sorted(). Лямбда-функции могут принимать любое количество аргументов, но содержат только одно выражение.


В чем отличие позиционных аргументов от именованных?

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


Лямбда функции, зачем нужны и чего точно не может быть в них?

Лямбда-функции в Python - это анонимные (безымянные) функции, которые могут содержать только одно выражение. Они полезны в случаях, когда требуется передать небольшую функцию в качестве аргумента другой функции или создать функцию на лету без необходимости определения ее имени.

Вот основные применения лямбда-функций:

Передача функции в качестве аргумента:
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, numbers))

Альтернатива map() с lambda: списковое включение без отдельной функции.

numbers = [1, 2, 3, 4, 5]
squared = [x**2 for x in numbers]
Создание коротких функций на лету:
add = lambda x, y: x + y

Чем пространство имен отличается от области видимости?

Пространство имен хранит соответствие имен объектам, например словарь глобальных имен модуля. Область видимости определяет участок программы и порядок, в котором эти пространства ищутся. Для функций действует LEGB: local, enclosing, global, built-ins. global направляет присваивание в пространство модуля, а nonlocal в ближайшую охватывающую функцию. Они меняют место привязки имени, а не сам объект. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Как Python ищет имя по правилу LEGB?

Python ищет имя в local, затем в enclosing-функциях, global-пространстве модуля и built-ins. Если в теле функции есть присваивание имени, компилятор считает его локальным, пока не объявлены global или nonlocal. Поэтому чтение такого имени до присваивания дает UnboundLocalError, а полное отсутствие имени дает NameError. Поиск атрибутов объекта устроен отдельно и правилу LEGB не подчиняется. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Как работает замыкание и зачем нужен nonlocal?

Замыкание сохраняет не снимок значения, а ячейку переменной из охватывающей функции, поэтому она живет после завершения внешнего вызова. Несколько внутренних функций могут видеть одну ячейку. Имена разрешаются при вызове, что создает эффект позднего связывания в циклах; текущее значение можно зафиксировать аргументом по умолчанию. nonlocal нужен для перепривязки этой переменной, а изменение уже захваченного списка возможно и без него. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Почему изменяемый аргумент по умолчанию сохраняет состояние?

Значение аргумента по умолчанию вычисляется один раз при выполнении def, а не при каждом вызове. Поэтому список или словарь накапливает изменения между вызовами. Обычно ставят None и создают объект внутри функции. Если None является допустимым значением, используют отдельный sentinel-объект, чтобы различать отсутствие аргумента и явно переданный None. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Когда уместен *args и чем он усложняет интерфейс функции?

*args собирает лишние позиционные аргументы в кортеж и удобен в обертках, делегировании и функциях с естественным переменным числом элементов. Тем же синтаксисом последовательность распаковывают при вызове. Для обычного публичного API явные параметры лучше: они видны в подсказках, документируют смысл и позволяют анализатору проверить вызов. Обязательные значения не стоит прятать в безымянной позиции args. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Когда уместен **kwargs и как не потерять контракт функции?

**kwargs собирает дополнительные именованные аргументы в словарь; при вызове словарь тем же синтаксисом распаковывают. Это уместно в декораторах и адаптерах, которые прозрачно передают параметры дальше. Собственный API должен явно объявлять обязательные и устойчивые параметры. Если набор дополнительных ключей ограничен, его проверяют и типизируют, например через TypedDict; молчаливое игнорирование опечатки превращает ошибку в скрытое поведение. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Какие объекты в Python можно вызывать?

Вызывать можно функции, связанные методы, классы и экземпляры, класс которых реализует __call__. Класс при вызове создает экземпляр через __new__ и __init__. callable(obj) проверяет только наличие механизма вызова. Он не гарантирует, что объект примет конкретные аргументы или что вызов завершится успешно; совместимость сигнатуры проверяет типизатор либо inspect.signature там, где интроспекция поддерживается. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Что входит в сигнатуру функции?

Сигнатура задает порядок и виды параметров: positional-only, positional-or-keyword, var-positional, keyword-only и var-keyword, а также значения по умолчанию и аннотации. inspect.signature() показывает их и умеет связывать набор аргументов. Для связанного метода self уже привязан и обычно не виден вызывающему. Аннотация возврата относится к метаданным функции, но Python не обеспечивает ее соблюдение автоматически. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Как работают positional-only и keyword-only параметры?

Символ / завершает positional-only параметры, а * начинает keyword-only параметры. Первые полезны, когда имя аргумента не является частью публичного API; вторые делают смысл вызова явным и позволяют безопаснее добавлять параметры. Python связывает каждый аргумент ровно один раз: передача значения и позиционно, и по имени дает ошибку, как и неизвестное имя без **kwargs. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Почему append не требует global, а присваивание требует?

append изменяет объект, на который уже указывает найденное глобальное имя, и не создает локальную привязку. Обычное присваивание имени внутри функции делает его локальным, если не указать global. += является ловушкой: для list он часто мутирует объект, но операция все равно включает присваивание имени и потому подчиняется правилам области видимости. Для внешней функции аналогично применяют nonlocal. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.


Чем чистая функция полезна в backend-коде?

Чистая функция при одинаковых аргументах дает одинаковый результат и не меняет наблюдаемое внешнее состояние. Ее проще тестировать, кэшировать и безопасно повторять. В backend полностью убрать эффекты нельзя, поэтому I/O, часы и случайность оставляют на границах, а правила расчета передают чистым функциям как данные. Это также делает транзакционные и retry-сценарии понятнее. На собеседовании полезно отдельно назвать момент связывания имени и отличить изменение объекта от новой привязки.

Собеседования: Python

Смотри записи интервью, узнай, какие вопросы задают и как отвечают кандидаты.

Вопросы и ответы

Не нашли ответ? Напишите мне в чат. Я делаю Шпаргалку и сам отвечаю на сообщения. Расскажите, что не работает или чего вам не хватает. Может, смогу сразу взять это в работу.

Откуда взяты вопросы?

Из реальных собеседований. Основой подборки стал опыт Вадима Новосёлова: он проходил интервью и записывал вопросы. Подробнее о материалах.

Насколько эти вопросы актуальны?

Эти вопросы встречались нам на реальных собеседованиях в 2025 году. Мы регулярно проходим собеседования и пополняем подборку новыми вопросами. Основы профессии и ключевые технологии остаются востребованными годами, а детали конкретных инструментов и версий стоит сверять с текущей документацией.

На какой уровень рассчитана подборка?

Мы проходили собеседования на вакансии уровня Middle+, а иногда и на Senior-позиции. Вопросы из этих интервью вошли в подборку. Направления работы: Python-разработчик, Backend-разработчик на Python. Глубина обсуждения зависит от вакансии: будь готов объяснить основную идею, привести практический пример и разобрать ограничения и альтернативы решения.

Этот вопрос точно будет на моём собеседовании?

Гарантии нет: набор вопросов зависит от компании, задач команды, уровня вакансии и самого интервьюера. Эти вопросы уже встречались на реальных собеседованиях, но на твоём интервью ту же тему могут проверить другой формулировкой, практической задачей или обсуждением твоего опыта. Используй подборку, чтобы разобраться в теме: объясняй идею своими словами, приводи примеры и готовься обсудить ограничения и альтернативы решения. Так будет проще ответить и на знакомый вопрос, и на неожиданные уточнения.