Руководство по использованию *args и **kwargs в Python

Вероятно, при чтении документации к функциям вам случалось увидеть странные параметры – *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”.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *