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

Використовуйте це для булевих прапорців та інших аргументів, де голе значення на місці виклику не було б самоочевидним.