ПрограммированиеBackend разработчик

Как работает механизм работы с аргументами позиционными и ключевыми (positional and keyword arguments) в Python? Какие есть нюансы порядка аргументов при определении функции и вызове, и для чего нужны только позиционные и только именованные параметры?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

В Python у функции можно объявлять параметры четырёх видов: позиционные, именованные (keyword), только позиционные (positional-only) и только именованные (keyword-only). Их различие влияет на способ передачи значений при вызове функции.

Типы параметров

  1. Позиционные (обычно идут первыми): значения передаются в порядке указания.
  2. Именованные: явно указываются через имя.
  3. Только позиционные: объявляются до символа / (Python 3.8+), нельзя задавать по имени.
  4. Только именованные: объявляются после *, можно задать только по ключу.
# Пример всех типов def func(a, b, /, c, *, d, e): print(a, b, c, d, e) func(1, 2, 3, d=4, e=5) # OK # func(a=1, b=2, 3, d=4, e=5) # Ошибка: a, b - только позиционные

Нюансы

  • Порядок параметров: (only-positional) / (positional-or-keyword) * (only-keyword)
  • При ошибочном порядке аргументов — SyntaxError или TypeError.
  • *args собирает доп. позиционные; **kwargs — именованные.

Вопрос с подвохом.

Чем различаются объявления функций:

def f(a, b, c): ... def f(a, b, c=1): ... def f(a, b=1, c=2): ... def f(a=1, b=2, c=3): ...

и правда ли, что все эти функции можно вызывать и с позиционными, и с ключевыми параметрами?

Ответ:

  • Для функции def f(a, b, c): нельзя вызвать с ключевыми только аргументами, потому что все можно передать как по позиции, так и по ключу, но все аргументы обязательны.
  • Можно указывать параметры по имени, если они не определены как только позиционные.
  • Если функция объявлена как def f(a, b, /, c):, то a и b можно только по позиции.

Пример:

def f(a, b, c=10): print(a, b, c) f(1, 2) # OK, c=10 по умолчанию f(a=1, b=2, c=3) # OK # А вот: def f(a, b, /, c=10): ... f(1, 2) # OK f(a=1, b=2, c=3) # Ошибка! a и b только позиционно

Примеры реальных ошибок из-за незнания тонкостей темы


История

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


История

В проекте с REST API из-за неявного соглашения о порядке аргументов (использовали *args и не ограничивали параметры по имени) перестали работать запросы после внедрения новой версии клиента — потому что args сместились. Исправили введением явных * и указанием только именованных аргументов.


История

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