# Understanding *args & **kwargs in Python: Best Practices and Guide

When we see the documentation of any function that contains \***args** and \*\***kwargs**, have you ever wondered - What are these strange parameters passed inside that function?

As an example:

`function(params, *args, **kwargs)`

As a beginner, you might get confused about how to use that function or what to pass as an argument in place of \***args** and \*\***kwargs** when calling that function.

Well not to worry, in this tutorial we gonna discuss `*args` and `**kwargs` - **What they mean** and **their uses in the function with examples** that help you to understand better.

**And we gonna see the glimpse of** `*` and `**` **(Unpacking operators) used in the examples.**

## Introduction

The function in Python helps us to write code that is reused, to perform particular tasks in various operations.

Let's define a function that prints the character names.

**Example:** `function` that prints character names

```python
def characters(name1, name2, name3):
    print(name1, name2, name3)

characters("Iron Man", "Black Panther", "Captain America")
```

**Output**

```bash
Iron Man Black Panther Captain America
```

The function `characters` above takes 3 positional arguments `name1`, `name2`, `name3` and simply prints the names.

What if we pass more than the number of arguments that it takes

```python
def characters(name1, name2, name3):
    print(name1, name2, name3)

characters("Iron Man", "Black Panther", "Captain America", "Hulk")
```

What do you think the output would be, the output will be a `TypeError`.

```bash
TypeError: characters() takes 3 positional arguments but 4 were given
```

The error was raised because of the extra argument passed inside the function, which only accepts three arguments.

That's unfortunate because we need to pass one more argument inside the function `character` in order for the code to run without error.

However, this is not the best practice. For example, suppose you are working on a project where you need to add multiple arguments dynamically when calling a specific function.

What should you do in such situations? There is a way to deal with such situations.

## Usage of \*args

`*args` is simply shortened for **arguments**. It is used as an argument when we are not sure how many arguments should we pass in the `function`.

**The** `*` asterisk before the `args` ensures that the argument has a variable length.

`*args` is a **Non-keyword argument** or **Positional argument**.

By using `*args`, you are allowed to pass any number of arguments when calling a function.

Example: Using `*args` in function definition

```python
def friends(*args):
    print(args)

friends("Sachin", "Rishu", "Yashwant", "Abhishek")
```

**Output**

```bash
('Sachin', 'Rishu', 'Yashwant', 'Abhishek')
```

We got `Tuple` because when we use `*args` the function will get the arguments as `tuple`.

If we check the type.

```python
def friends(*args):
    print(type(args))
    print(args)

friends("Sachin", "Rishu", "Yashwant", "Abhishek")
```

**Output**

```bash
<class 'tuple'>
('Sachin', 'Rishu', 'Yashwant', 'Abhishek')
```

We can also use regular arguments with `*args`.

Example: Using regular arguments and args in the function definition

```python
def friends(greet, *args):
    for friend in args:
        print(f"{greet} to Python, {friend}")

greet = "Welcome"
friends(greet, "Sachin", "Rishu", "Yashwant", "Abhishek")
```

**Output**

```bash
Welcome to Python, Sachin
Welcome to Python, Rishu
Welcome to Python, Yashwant
Welcome to Python, Abhishek
```

**Note: You can use any name you want instead of** `args`**, including your pet's name, a friend's name, or even your girlfriend's name, as long as you put a** `*` **before it.**

Example: Using a different name instead of args

```python
def dog(prefix, *german_shepherd):
    for breed in german_shepherd:
        print(f"The {prefix} is {breed}.")

prefix = "breed"
dog(prefix, "Labrador", "GSD", "Chihuahua")
```

**Output**

```bash
The breed is Labrador.
The breed is GSD.
The breed is Chihuahua.
```

There is one exception: when passing regular arguments and `*args` as parameters to a function, never pass `*args` before regular arguments.

Example: Using `*args` before regular argument inside the function

```python
def heroes(*characters, country):
    for character in characters:
        print(f"{character} is from {country}.")

country = "USA"
heroes(country, "Iron Man", "Captain America", "Spiderman")
```

**Output**

```bash
TypeError: heroes() missing 1 required keyword-only argument: 'country'
```

We got a `TypeError` because we cannot pass `*args` before the regular argument.

There will be no error if we change the code and move the parameters passed inside the function.

```python
def heroes(country, *characters):
    for character in characters:
        print(f"{character} is from {country}.")

country = "USA"
heroes(country, "Iron Man", "Captain America", "Spiderman")
```

**Output**

```bash
Iron Man is from USA.
Captain America is from USA.
Spiderman is from USA.
```

The above code was executed without any error.

## Usage of \*\*kwargs

`**kwargs` is shortened for **Keyword argument**.

Now you are familiar with `*args` and know its implementation, `**kwargs` works similarly as `*args`.

But unlike `*args`, `**kwargs` takes **keyword** or **named** arguments.

In `**kwargs`, we use `**` double asterisk that allows us to pass through keyword arguments.

Example: Using `**kwargs` in the function definition

```python
def hello(**kwargs):
    print(type(kwargs))
    for key, value in kwargs.items():
        print(f"{key} is {value}.")

hello(One = "Red", two = "Green", three = "Blue")
```

**Output**

```bash
<class 'dict'>
One is Red.
two is Green.
three is Blue.
```

The `type` of `**kwargs` is **Dictionary** i.e., the arguments accepted as `key-value`.

Example: Using regular argument and `**kwargs` together inside the function definition

```python
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")
```

**Output**

```bash
RGB stands for:
One is Red.
two is Green.
three is Blue.
```

Just like `*args`, you can choose any name instead of `**kwargs`

Example: Using a different name instead of kwargs

```bash
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")
```

**Output**

```bash
RGB stand for:
One is Red.
two is Green.
three is Blue.
```

Note: We cannot pass `**kwargs` before `*args` in the function definition otherwise, we'll get a `SyntaxError`.

***The convention should be -*** `function(params, *args, **kwargs)`

## Example

We can use all three types of arguments inside the function definition and in this example, we'll see the use of the **unpacking operator** - `*` and `**`.

```python
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)
```

**Output**

```bash
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
```

You'll notice that the variables called `names` and `roles` in the above code were used.

However, we put `*` before the `names` variable and `**` before the `roles` variable when we passed them inside the function.

These are the **Unpacking operators**.

### Unpacking Operator

These operators come quite in handy as you saw above.

`*` single asterisk is used to unpack iterable and `**` double asterisk is used to unpack dictionary.

> The `*` iterable unpacking operator and `**` dictionary unpacking operators to allow unpacking in more positions, an arbitrary number of times, and in additional circumstances. Specifically, in function calls, in comprehensions and generator expressions, and in displays. [Source](https://www.python.org/dev/peps/pep-0448/)

To know more, click [here](https://www.python.org/dev/peps/pep-0448/)

---

## Conclusion

So far you will now be able to implement the fundamentals of `*args` and `**kwargs` inside the functions.

These might come in handy when you are working on projects where data comes dynamically in a function and you don't know how many arguments to be passed in that function. This makes your project scalable.

---

🏆**Other articles you might be interested in if you liked this one**

✅[Context managers and the with statement in Python](https://geekpython.in/context-managers-and-python-with-statement).

✅[Display local and web images in the Jupyter Notebook](https://geekpython.in/display-images-in-jupyter-notebook).

✅[Public, Protected, and Private access modifiers in Python](https://geekpython.in/access-modifiers-in-python).

✅[How to change the string representation of the objects using the str and repr method](https://geekpython.in/str-and-repr-in-python)?

✅[What is enumerate() function in Python](https://geekpython.in/python-enumerate-function-with-example-beginners-guide)?

✅[Execute dynamically generated code using the exec() in Python](https://geekpython.in/exec-function-in-python).

✅[Difference between the reverse() and the reversed() function in Python](https://geekpython.in/reverse-vs-reversed-in-python).

---

**That's all for now**

**Keep Coding✌✌.**
