Функции и аргументы: вопросы для собеседования (часть 3)
Позиционные и именованные аргументы, *args, **kwargs, значения по умолчанию, замыкания, lambda — всё это спрашивают на собеседованиях. Частая ловушка — мутабельный объект как значение по умолчанию. Умение декомпозировать код на функции и правильно работать с аргументами — признак зрелого разработчика.
Вопросы 11–15 из 20
11Дана функция `def add(a, b, c): return a + b + c` и список `nums = [1, 2, 3]`. Что вернёт вызов `add(*nums)`?
AЧисло `6` после распаковки `nums` в позиционные `a=1`, `b=2`, `c=3`
BЧисло `1` после передачи в `a` только первого элемента списка `nums`
CКортеж `(1, 2, 3)` без распаковки: `nums` уйдёт в `a` как один объект
DОшибка `TypeError`: `add` не принимает список `nums` как один аргумент
Ответ: Оператор `*` при вызове функции распаковывает список в позиционные аргументы.
Вызов `add(*nums)` эквивалентен `add(1, 2, 3)`: элементы списка подставляются как позиционные аргументы. Поэтому результат — 6. Если бы количество элементов в списке не совпало с числом параметров, возник бы `TypeError`. Распаковка через `*` полезна, когда аргументы уже собраны в список или кортеж, но функция принимает их позиционно.
Подробный разбор → 12Дана функция `def endpoint(path, **kwargs): return kwargs`. Что вернёт вызов `endpoint('/users', limit=10, sort='asc')`?
AСписок `['limit', 'sort']` из имён переданных именованных аргументов без значений
BКортеж `('limit', 10, 'sort', 'asc')` с чередованием имён и значений аргументов
CСловарь `{'limit': 10, 'sort': 'asc'}` с сопоставлением имён и значений аргументов
DМножество `{'limit', 'sort'}` из имён переданных именованных аргументов без значений
Ответ: `**kwargs` собирает именованные аргументы в словарь, где ключ — имя параметра, а значение — переданное значение.
Параметр `**kwargs` собирает все именованные аргументы, которые не перечислены явно, в словарь. В примере `kwargs` будет равен `{'limit': 10, 'sort': 'asc'}`. Это удобно для функций-обёрток, журналирования, проброса опций и построения гибких интерфейсов, но злоупотреблять не стоит: основные параметры лучше делать явными, чтобы сигнатура функции оставалась читаемой.
Подробный разбор → 13Дана функция `def total(*args): return sum(args)`. Что вернёт вызов `total(1, 2, 3)`?
AЧисло `3`: `*args` собирает только последний переданный аргумент в одну переменную
BКортеж `(1, 2, 3)`: функция вернёт сам кортеж аргументов без вызова `sum()` над ним
CСписок `[1, 2, 3]`: `*args` создаёт список и `sum()` отдаёт его без изменений
DЧисло `6`: `*args` собирает аргументы в кортеж `(1, 2, 3)`, и `sum()` суммирует их
Ответ: `*args` собирает позиционные аргументы в кортеж, а `sum(args)` суммирует их.
Параметр `*args` означает «собери все позиционные аргументы в одну переменную `args`», и внутри функции это будет кортеж `(1, 2, 3)`. Затем `sum(args)` возвращает сумму элементов кортежа, то есть 6. Такой приём удобен, когда заранее не известно, сколько значений передадут в функцию.
Подробный разбор → 14Что произойдет при выполнении `x = 1; def foo(): x = x + 1; return x; foo()`?
A`RecursionError`
B`AttributeError`
C`UnboundLocalError`
D`RuntimeError`
Ответ: Если внутри функции есть присваивание имени, Python считает его локальным; чтение до присваивания приводит к `UnboundLocalError`.
Внутри `foo()` есть присваивание `x = ...`, поэтому `x` считается локальной переменной. Но выражение справа `x + 1` пытается прочитать локальный `x` до того, как ему присвоено значение. Это приводит к `UnboundLocalError`. Чтобы изменить глобальную переменную, нужен `global x`, а чтобы избежать побочных эффектов — лучше возвращать новое значение и присваивать его снаружи.
Подробный разбор → 15В коде `count = 0; def inc(): global count; count += 1; return count` зачем используется `global count`?
AЧтобы сделать `count` неизменяемой константой и запретить любые присваивания внутри функции
BЧтобы скопировать значение `count` в локальную переменную и работать с независимой копией внутри функции
CЧтобы ускорить выполнение функции за счёт прямого доступа к глобальной памяти без поиска по областям видимости
DЧтобы указать, что `count` относится к глобальной области и его можно изменять внутри функции
Ответ: `global` нужен, когда внутри функции вы присваиваете значение глобальной переменной, иначе Python считает её локальной.
Если внутри функции есть присваивание `count += 1`, Python по умолчанию считает `count` локальным именем. Тогда попытка прочитать его до присваивания приведёт к ошибке `UnboundLocalError`. Команда `global count` говорит интерпретатору использовать глобальную переменную и позволяет изменять её внутри функции. В большинстве случаев лучше избегать глобального состояния и возвращать новое значение, но иногда `global` уместен в простых скриптах.
Подробный разбор →