Функции с переменным числом аргументов; 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 так исторически сложилось, что подобные переменные называют именно так. Ничто не мешает называть их по-другому, но остальным проще будет читать код, если при написании Вы не будете отходить от общепринятых соглашений.