# \*args и \*\*kwargs

Я много раз замечал, что у новых Python разработчиков вызывают трудности магические переменные \*args и \*\*kwargs. Так что же они из себя представляют? Во-первых, позвольте сказать, что вам не обязательно называть их именно \*args и \*\*kwargs. Только `*` (звездочка) действительно необходима. К примеру, их можно назвать \*var и \*\*vars. Использование \*args и \*\*kwargs идет на уровне соглашения между разработчиками. Теперь давайте начнём рассказ с \*args.

## Использование \*args

\*args и \*\*kwargs в основном используются в определениях функций. \*args и \*\*kwargs позволяют передавать им произвольное число аргументов. Под произвольным числом здесь понимается ситуация, когда вы не знаете заранее сколько аргументов может быть передано функции пользователем, поэтому в данном случае вам необходимо использовать эти ключевые слова. \*args используется для передачи произвольного числа **неименованных** аргументов функции. Вот пример, чтобы помочь вам понять идею:

```python
def test_var_args(f_arg, *argv):
    print("Первый позиционный аргумент:", f_arg)
    for arg in argv:
        print("Другой аргумент из *argv:", arg)

test_var_args('yasoob', 'python', 'eggs', 'test')
```

Результат будет таким:

```
Первый позиционный аргумент: yasoob
Другой аргумент из *argv: python
Другой аргумент из *argv: eggs
Другой аргумент из *argv: test
```

Надеюсь, пример развеял возможную путаницу. Теперь перейдем к разговору о \*\*kwargs

## Использование \*\*kwargs

\*\*kwargs позволяет вам передавать произвольное число **именованных** аргументов в функцию. Таким образом, вам необходимо использовать \*\*kwargs там, где вы хотите работать с **именованными** аргументами. Очередной пример:

```python
def greet_me(**kwargs):
    for key, value in kwargs.items():
        print("{0} = {1}".format(key, value))

>>> greet_me(name="yasoob")
name = yasoob
```

В результате, мы оперируем произвольным числом именованных аргументов в нашей функции. Это были основы использования \*\*kwargs и можете сами отметить насколько это может быть удобно в определенных ситуациях. Теперь давайте рассмотрим использование \*args и \*\*kwargs для передачи в функцию списка или словаря аргументов.

## Использование \*args и \*\*kwargs при вызове функции

Рассмотрим вызов функции, используя \*args и \*\*kwargs. Пусть у нас есть вот такая небольшая функция:

```python
def test_args_kwargs(arg1, arg2, arg3):
    print("arg1:", arg1)
    print("arg2:", arg2)
    print("arg3:", arg3)
```

Мы можем использовать \*args или \*\*kwargs чтобы передать в неё аргументы. Вот как мы это сделаем:

```python
# Сначала с *args
>>> args = ("two", 3, 5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5

# Теперь с **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two", "arg1": 5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3
```

## Порядок использования \*args, \*\*kwargs и формальных параметров

Если вы хотите использовать все три метода в функции, то порядок должен быть таким:

```python
some_func(fargs, *args, **kwargs)
```

## Когда их использовать?

Все зависит от ваших потребностей. Наиболее часто \*args и \*\*kwargs используются при написании декораторов (подробнее о декораторах в другой главе). Помимо этого данная методика может использоваться для "monkey patching". Под "monkey patching" понимается модификация кода во время выполнения программы. Предположим, у нас есть класс с методом `get_info`, который обращается к API и возвращает данные ответа. Для тестирования этого метода мы можем заменить вызов API и искусственно возвращать определенные тестовые данные. Например:

```python
import someclass

def get_info(self, *args):
    return "Test data"

someclass.get_info = get_info
```

Уверен, вы можете придумать и другие подходящие сценарии использования.
