Функции с переменным числом аргументов; args, kwargs
Допустим, мы хотим написать функцию, которая выводит среднее арифметическое всех своих аргументов. Мы можем, используя предыдущие знания, написать эту функцию, например, для трёх аргументов:
def mean(elem1, elem2, elem3): return (elem1 + elem2 + elem3) / 3
Или для четырёх. Или для двух. Но только для какого-то конкретного известного заранее количества аргументов
Можно сказать, что мы будем принимать только 1 аргумент - список со значениями; и пусть вызывающий засовывает все переменные в массив перед вызовом функции.
Распаковка позиционных аргументов, args
Однако в Python есть способ передавать произвольное количество аргументов. Делается это через оператор распаковки:
def mean(*args): return sum(args) / len(args)
Что же происходит в строке def mean(*args)? Аргументы распаковываются в переменную args.
После распаковки переменная args будет содержать кортеж со значениями аргументов.
Можно распаковывать не все аргументы, а лишь последние переданные. Например, код ниже распечатает среднее арифметическое всех аргументов, кроме первого:
a = 10 b = c = d = 1 def mean(first, *args): return sum(args) / len(args) print(mean(a, b, c, d))
Распаковка аргументов напоминает распаковку кортежа, где кортеж - это аргументы, которые мы передадим при вызове. Сравните:
a = 10 b = c = d = 1 def mean(first, *args): return sum(args) / len(args) print(mean(a, b, c, d))
и
a = 10 b = c = d = 1 def mean(first, args): return sum(args) / len(args) a, *args = (a, b, c, d) print(mean(a, args))
Распаковка именованных аргументов, kwargs
Также можно передавать произвольное количество именованных аргументов. Делается это также, как и с позиционными, только ставим мы теперь две звёздочки.
И распаковываться аргументы будут в словарь, где ключами служат имена аргументов, а значениями - значения аргументов:
def print_kwargs(**kwargs): return kwargs print(print_kwargs(a=1, b=2, c=3, d=4)) # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
Например, можно вернуть среднее арифметическое всех переменных, кроме a:
def mean(**kwargs): kwargs.pop("a", 0) return sum(kwargs.values()) / len(kwargs) print(mean(a=1, b=2, c=3, d=4))
args и kwargs можно комбинировать. Однако, как и в обычных функциях, сначала идут позиционные, а потом именованные аргументы. Например, среднее арифметическое всех аргументов:
def mean(*args, **kwargs): total = sum(args) + sum(kwargs.values()) length = len(args) + len(kwargs) return total / length print(mean(1, 1, new=4))
Почему переменные после распаковки называются args и kwargs соответственно? args - сокращение от arguments, kwargs - сокращение от keyword arguments.
В Python так исторически сложилось, что подобные переменные называют именно так. Ничто не мешает называть их по-другому, но остальным проще будет читать код, если при написании Вы не будете отходить от общепринятых соглашений.