Переменное число аргументов в Python. *args и **kwargs
Все знают, что у функций есть аргументы. Их может быть, скажем, 1 или 5, но что, если функция должна принимать сколько угодно аргументов? Допустим функция print: сколько аргументов ей ни передай, она всё равно все их обработает:
print(1,2,3) # 1 2 3
Давайте разберёмся, как такое можно реализовать.
Массив аргументов: *args
При объявлении функции, можно после всех основных аргументов указать ещё один, начинающийся со звёздочки. Обычно его называют args(сокр. от arguments). Например объявим следующую функцию:
def test_args(a, b, *args): pass
Она принимает 2 обязательных аргумента: a и b и любое число дополнительных аргументов, которые будут переданы в args. Все вызовы ниже корректны:
test_args(1, 2) # Указываем только a и b test_args(1, 2, 3, 4, 5) # a и b и 3 необязательных аргумента test_args(1, 2, 5) # 1 необязательный аргумент
В первом случае, args - пустой кортеж, во втором - (3,4,5), в третьем - (5). Значения идут в том порядке, в котором они были переданы.
Словарь аргументов: **kwargs
А что делать с именованными аргументами? По аналогии, после всех обязательных аргументов и args(если он есть) можно указать аргумент, который начинается с **, его принято называть kwargs(сокр. от keyword arguments). Это словарь всех значений, в котором ключ - имя аргумента, а ему соответствует значение аргумента. Рассмотрим следующую функцию:
def test_args_and_kwargs(a, *args, **kwargs): pass
Вызывать её можно так, например:
test_args_and_kwargs(1, 2, 3, first=1, second=2)
a будет равно 1
args равно (2, 3)
kwargs равно {"first":1, "second": 2}
Таким образом, можно сделать не только переменное число позиционных аргументов, но и именованных.
Распаковка аргументов
Не все знают, что есть точно такие же обозначения и при вызове функций. Рассмотрим пример:
print(*(1,2,3,4)) # Выведет 1 2 3 4
Такое ощущение, что print просто передали 4 аргумента, да? Вы правы. Дело в том, что если к массиву или кортежу дописать * в начале, то питон "распакует" значения в соответствующие аргументы. Причём это можно писать в любом месте. Например так:
print(1, 2, *(3, 4, 5), 6) # 1 2 3 4 5 6
Уже догадываетесь, что есть аналогия с kwargs? Чутьё вас не подводит:
print("HelloWorld", **{"end":"!!!"}) # Выведет HelloWorld!!!
Таким образом, можно передавать произвольное число именованных аргументов.
Вместо заключения
Эти синтаксические конструкции дают много простора для творчества. Однако, по возможности, старайтесь передавать аргументы явно: это упрощает код для чтения, и к вам возникнет меньше вопросов.
Статья для группы SnakeBlog