2.15. Аргументы

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

2.15.1. Позиционные и именованные аргументы

Самый простой вызов передаёт аргументы по позиции – первое значение идёт в первый параметр, второе во второй и так далее:

def rect(x, y, w, h):
    return (x, y, w, h)

rect(10, 20, 100, 50)

Тот же вызов может передавать аргументы по имени, явно называя каждый параметр:

rect(x=10, y=20, w=100, h=50)

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

rect(10, 20, w=100, h=50)         # OK
rect(x=10, 20, 100, 50)           # SyntaxError

2.15.2. Значения по умолчанию

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

def greet(name, greeting="hello"):
    print(greeting, name)

greet("Alice")                    # hello Alice
greet("Alice", "hi")              # hi Alice
greet("Alice", greeting="hey")    # hey Alice

Параметры со значениями по умолчанию должны идти после параметров без значений по умолчанию в строке def.

Предупреждение

Значения по умолчанию вычисляются один раз, при выполнении def – а не при каждом вызове. Использование изменяемого значения по умолчанию ([], {}) приводит к тому, что один и тот же объект разделяется между всеми вызовами, использующими значение по умолчанию. Вместо этого используйте None как индикатор-заглушку:

def append_to(item, target=None):
    if target is None:
        target = []
    target.append(item)
    return target

2.15.3. Переменное число: *args и **kwargs

Параметр с префиксом * собирает все оставшиеся позиционные аргументы в tuple. Параметр с префиксом ** собирает все оставшиеся именованные аргументы в dict. Общепринятые имена – args и kwargs, но подойдёт любой идентификатор:

def report(label, *values, **options):
    print(label, values, options)

report("temps", 21, 22, 23, unit="C", precision=1)

Вывод:

temps (21, 22, 23) {'unit': 'C', 'precision': 1}

Функции редко нужны оба сразу. Чаще всего это используется для передачи аргументов от обёртки к внутреннему вызову:

def log_and_call(func, *args, **kwargs):
    print("calling", func.__name__)
    return func(*args, **kwargs)

Зеркальный синтаксис на стороне вызова распаковывает итерируемый объект в позиционные аргументы (*) или dict в именованные аргументы (**):

point = (10, 20, 100, 50)
rect(*point)                      # same as rect(10, 20, 100, 50)

kwargs = {"x": 10, "y": 20, "w": 100, "h": 50}
rect(**kwargs)                    # same as rect(x=10, y=20, ...)

2.15.4. Только-именованные параметры

Одиночная * в списке параметров (не присоединённая к имени) помечает каждый следующий за ней параметр как только-именованный – вызывающая сторона обязана использовать имя:

def crop(buffer, *, x, y, w, h):
    ...

crop(buffer, x=0, y=0, w=100, h=100)   # OK
crop(buffer, 0, 0, 100, 100)           # TypeError

Используйте это для логических флагов и других аргументов, где голое значение на месте вызова было бы непонятным без пояснений.