Вероятно, при чтении документации к функциям вам случалось увидеть странные параметры — *args и **kwargs. Например, function(params, *args, **kwargs). И возможно, вы интересовались, что это за параметры.
В этой статье мы разберем, что собой представляют *args и **kwargs, а также рассмотрим примеры их применения.
Введение
С помощью функций в Python мы можем писать переиспользуемый код для выполнения определенных задач.
Давайте определим функцию, которая печатает имена киношных персонажей.
def characters(name1, name2, name3):
print(name1, name2, name3)
characters("Iron Man", "Black Panther", "Captain America")
# Вывод:
# Iron Man Black Panther Captain America
Функция characters принимает 3 позиционных аргумента — name1, name2, name3 — и просто печатает переданные ей данные.
Но что будет, если мы передадим не три аргумента, а больше? Скажем, четыре?
def characters(name1, name2, name3):
print(name1, name2, name3)
characters("Iron Man", "Black Panther", "Captain America", "Hulk")
# Вывод:
# TypeError: characters() takes 3 positional arguments but 4 were given
Мы получим ошибку TypeError.
Ошибка возникает из-за лишнего аргумента, переданного в функцию, которая принимает только три аргумента.
Чтобы код выполнялся без ошибок, нужно добавить еще один параметр в определении функции.
Однако это не самый лучший метод. Допустим, что вы работаете над проектом, в котором вам нужно динамически добавлять аргументы при вызове определенной функции.
Что делать в таких ситуациях? Решение есть!
Использование *args
«args» — это просто сокращение от arguments (русск. аргументы). *args используется в качестве параметра, когда мы не уверены, сколько аргументов нужно передать в функцию.
*args — это позиционный параметр.
Звездочка (*) перед args означает, что аргумент имеет переменную длину. Используя *args, при вызове функции можно передать любое количество аргументов.
Рассмотрим пример:
def friends(*args):
print(args)
friends("Sachin", "Rishu", "Yashwant", "Abhishek")
# Вывод:
# ('Sachin', 'Rishu', 'Yashwant', 'Abhishek')
Мы получили кортеж, потому что при использовании *args функция получит аргументы в виде кортежа.
Давайте проверим тип args:
def friends(*args):
print(type(args))
print(args)
friends("Sachin", "Rishu", "Yashwant", "Abhishek")
# Вывод:
# <class 'tuple'>
# ('Sachin', 'Rishu', 'Yashwant', 'Abhishek')
При определении функции вместе с *args можно использовать и другие параметры. Пример:
def friends(greet, *args):
for friend in args:
print(f"{greet} to Python, {friend}")
greet = "Welcome"
friends(greet, "Sachin", "Rishu", "Yashwant", "Abhishek")
Вывод:
Welcome to Python, Sachin Welcome to Python, Rishu Welcome to Python, Yashwant Welcome to Python, Abhishek
Примечание: вместо “args” можно использовать любое имя, включая кличку вашего питомца, имя друга или даже имя вашей девушки, если перед ним поставить символ *.
Давайте вместо args используем другое имя:
def dog(prefix, *german_shepherd):
for breed in german_shepherd:
print(f"The {prefix} is {breed}.")
prefix = "breed"
dog(prefix, "Labrador", "GSD", "Chihuahua")
Вывод:
The breed is Labrador. The breed is GSD. The breed is Chihuahua.
Важное примечание: если помимо *args вы передаете в фукнцию и обычные аргументы, при объявлении функции параметр *args должен идти после обычных.
Давайте для примера попробуем поставить *args перед обычным параметром:
def heroes(*characters, country):
for character in characters:
print(f"{character} is from {country}.")
country = "USA"
heroes(country, "Iron Man", "Captain America", "Spiderman")
# Вывод:
# TypeError: heroes() missing 1 required keyword-only argument: 'country'
Мы получили ошибку TypeError.
Но если мы изменим код и поменяем местами параметры в объявлении функции, ошибка не возникнет:
def heroes(country, *characters):
for character in characters:
print(f"{character} is from {country}.")
country = "USA"
heroes(country, "Iron Man", "Captain America", "Spiderman")
Вывод:
Iron Man is from USA. Captain America is from USA. Spiderman is from USA.
Использование **kwargs
«kwargs» — это сокращение от keyword arguments (русск. “аргументы с ключевыми словами”, обычно переводится как “именованные аргументы”).
**kwargs работает так же, как и *args. Но, в отличие от *args, **kwargs принимает не позиционные, а именованные аргументы.
В **kwargs мы используем двойную звездочку **, которая позволяет нам передавать именованные аргументы.
Пример использования **kwargs:
def hello(**kwargs):
print(type(kwargs))
for key, value in kwargs.items():
print(f"{key} is {value}.")
hello(One = "Red", two = "Green", three = "Blue")
Вывод:
<class 'dict'> One is Red. two is Green. three is Blue.
Тип **kwargs — словарь, то есть аргументы передаются в виде пар ключ-значение.
Как и *args, **kwargs можно использовать совместно с обычными аргументами. Пример:
def hello(write, **kwargs):
print(write)
for key, value in kwargs.items():
print(f"{key} is {value}.")
write = "RGB stands for:"
hello(write, One = "Red", two = "Green", three = "Blue")
Вывод:
RGB stands for: One is Red. two is Green. three is Blue.
Также вместо **kwargs можно использовать любое другое имя:
def hello(write, **color):
print(write)
for key, value in color.items():
print(f"{key} is {value}.")
write = "RGB stand for:"
hello(write, One = "Red", two = "Green", three = "Blue")
Вывод:
RGB stand for: One is Red. two is Green. three is Blue.
Примечание: нельзя передавать **kwargs перед *args в определении функции, иначе получим SyntaxError.
По правилам порядок должен быть таким: function(params, *args, **kwargs). Т.е. сначала идут обычные параметры, потом *args, потом **kwargs.
Пример использования обычных параметров вместе с *args и **kwargs
При определении функции мы можем использовать все три типа параметров.
def friends(greet, *args, **kwargs):
for names in args:
print(f"{greet} to the Programming zone {names}")
print("\nI am Veronica and I would like to announce your roles:")
for key, value in kwargs.items():
print(f"{key} is a {value}")
greet = "Welcome"
names = ["Sachin", "Rishu", "Yashwant", "Abhishek"]
roles = {"Sachin":"Chief Instructor", "Rishu":"Engineer",
"Yashwant":"Lab Technician", "Abhishek":"Marketing Manager"}
friends(greet, *names, **roles)
Вывод:
Welcome to the Programming zone Sachin Welcome to the Programming zone Rishu Welcome to the Programming zone Yashwant Welcome to the Programming zone Abhishek I am Veronica and I would like to announce your roles: Sachin is a Chief Instructor Rishu is a Engineer Yashwant is a Lab Technician Abhishek is a Marketing Manager
Вы, верно, заметили, что в приведенном выше коде использовались переменные names и roles. Однако мы поставили * перед переменной names и ** перед переменной roles, когда передавали их в функцию.
* и ** — это операторы распаковки.
Оператор распаковки
Эти операторы очень полезны, как вы видели выше.
Одинарная звездочка (*) используется для распаковки итерируемых объектов, а двойная звездочка (**) — для распаковки словаря.
Операторы * и ** позволяют выполнять распаковку в вызовах функций, в представлениях (comprehensions) и генераторных выражениях (источник).
Заключение
Теперь, зная, что собой представляют *args и **kwargs в параметрах функций, вы можете попробовать применить их в собственном коде.
Эти параметры могут пригодиться вам при работе над проектами, в которых данные поступают в функцию динамически, и вы не знаете, сколько аргументов нужно передать.
Перевод статьи “Understanding args and kwargs in Python: Best Practices and Guide”.
