SoFunction
Updated on 2025-04-11

A post thoroughly understands Python magic parameters args and kwargs (easy to understand)

Today, let’s talk about two “magic parameters” in Python function parameters - *args and **kwargs, which can make your functions super flexible and easily deal with various complex situations. However, it is a difficult concept for students who are new to Python. Up also felt that it was too flexible and difficult to understand for the first time. Today, Up tryIn easy-to-understand language, make it clear

Lay the key points in advance

  • What are positional parameters and keyword parameters?
  • *args is essentially a tuple
  • **kwargs is essentially a dictionary
  • How to use *args and **kwargs in combination
  • Use * args and **kwargs in decorators

Position parameters and keyword parameters

Before we get to know * args and **kwargs, we have to familiarize ourselves with the two "regular armies" in Python function parameters - positional parameters and keyword parameters, which are the basis for function parameter transfer.

Position parameters, as the name implies, is when calling a function,In order of parametersThe parameters passed to the function in sequence, the positions of the actual parameters and the positions of the formal parameters must correspond one by one.Just like queuing up to get things, the first one comes first, the order cannot be messed up. For example, let's define a function that calculates the sum of two numbers:

def add_numbers(a, b):
    return a + b

Here a and b are positional parameters. When we call this function, we have to pass in two numbers in order:

result = add_numbers(3, 5)
print(result)  

In this example, 3 will be assigned to a, 5 will be assigned to b, and the function returns their sum 8.

andKeyword parametersThat's much more flexible. It refers to when calling a function,Assign values ​​to parameters by specifying parameter names, so that you don’t have to stick to the position order of parameters, making the code clearer and easier to read. Let’s use the addition function just now as an example, we can call it like this:

result = add_numbers(a=3, b=5)

Even the order of exchange is possible:

result = add_numbers(b=5, a=3)

Regardless of the order, as long as the parameter name is written correctly, the value can be assigned to the corresponding formal parameters accurately. Isn’t it very convenient? This is especially useful when there are many function parameters, allowing you to understand the meaning of each parameter at a glance.

in addition,Position parameters and keyword parameters can also be used in a mixture, but one rule to remember:Position parameters must be before keyword parameters. for example:

def greet(name, message):
    print(f"{message}, {name}!")

greet("Xiao Ming", message="Hello") 

It is fine to write this way, but if you write it as greet(message="Hello", "Xiao Ming"), Python will report an error because it violates the principle of positional parameters first.

*args is essentially a tuple

*args is like a “Parameter collector”, it can collect the extra position parameters when calling a function, and thenPackage into a tuple. Pay attention here. The name does not necessarily have to be args. It is okay to write it as numbers, values, etc. The key is that the asterisk, which is like a "magic mark", telling Python: "Hey, I want to collect extra position parameters!"

Let's take a look at an example. If you want to write a function to calculate the sum of any number, you are not sure how many numbers the user will enter. At this time, * args can show off your skills:

def sum_numbers(*args):
    total = 0
    for number in args:
        total += number
    return total

In this function, *args is like a pocket, no matter how many position parameters you pass in, it can catch them.Then turn these parameters into a tuple. For example, let's call this function like this:

result = sum_numbers(1, 2, 3, 4, 5)
print(result)  

The 1, 2, 3, 4, 5 passed here will be collected by * args and become tuples (1, 2, 3, 4, 5). Then, within the function, loop through this tuple, add each number to the sum, and finally get the sum of 15.

**kwargs is essentially a dictionary

After talking about *args, let’s take a look at another protagonist—**kwargs. It also has a magical "magic mark" - two asterisks**. With it, the function can pass any number of callsKeyword parametersCollect all of them,Organize into a dictionary (dict). Like * args, the name is not fixed, and it is OK to write it as **params, **options, etc., the key is the two asterisks.

Let's take a look at an example. If you want to write a function to show a person's detailed information, you don't know what specific information the user will provide. At this time, **kwargs will come in handy:

def show_person_info(**kwargs):
    for key, value in ():
        print(f"{key}: {value}")

In this function, **kwargs is like a universal information storage box. It can catch no matter how many keyword parameters you pass in.Then turn these parameters into a dictionary. For example, let's call this function like this:

show_person_info(name="Xiao Ming", age=20, city="Beijing")

The name="Xiao Ming", age=20, city="Beijing" passed here will be collected by **kwargs and become a dictionary {"name": "Xiao Ming", "age": 20, "city": "Beijing"}, and then inside the function, by traversing the dictionary, print out each key-value pair, showing the detailed information of this person.

From a function definition point of view, **kwargs must also be placed at the end of the parameter list, which is to allow the Python interpreter to correctly identify the parameters. If you put it in front, the parameters behind may be mistaken for keyword parameters, causing the program to make an error.

How to use *args and **kwargs

After understanding the characteristics of * args and **kwargs, let's see how to combine them.

In actual programming, there are many scenarios that require the processing of positional parameters and keyword parameters at the same time, and the number is still uncertain. For example, you want to write a function to record log information. The log may contain some fixed format information (similar to keyword parameters), and may also have some additional description information (similar to position parameters). At this time, * args and **kwargs can work perfectly.

Let's take a look at an example:

def log_message(message_type, *args, **kwargs):
    print(f"[{message_type}]")
    for arg in args:
        print(arg)
    for key, value in ():
        print(f"{key}: {value}")

In this log_message function, message_type is a fixed positional parameter used to specify the type of the log, such as "ERROR", "INFO", etc. *args is used to receive some additional description information, while **kwargs is used to receive some detailed information with specific names, such as the time when the log occurs, the number of lines of code, etc.

Let's call this function like this:

log_message("INFO", "Program started successfully", time="2023-09-15 10:00:00", line_number=100)

Here, "Program Start Successfully" will be collected by args and become a tuple ("Program Start Successfully"), while time="2023-09-15 10:00:00" and line_number=100 will be collected by **kwargs and become dictionary {"time": "2023-09-15 10:00:00", "line_number": 100}. The log type "INFO" is first printed inside the function, then traverse *args to print the additional description, and then traverse **kwargs to print the detailed information, and the output will look like this:

[INFO]
The program starts successfully
time: 2023-09-15 10:00:00
line_number: 100

Use * args and **kwargs in decorators

After talking about the basic usage of * args and **kwargs, let’s take a look at how they are used in the decorator!

For those who are not familiar with decorators, you can read the article from Up last issue!

So what role do *args and **kwargs play in the decorator? Imagine that if the decorated function may receive an uncertain number of parameters, just like the usage of *args and **kwargs we mentioned earlier, the internal functions in the decorator must use *args and **kwargs to receive these parameters, and then pass them to the original function intact, otherwise the parameters will not be passed in, which will cause an error.

Let's take a look at an example. Suppose you want to write a decorator to record the execution time of the function. No matter how many parameters this function receives, it will work normally:

import time

def timeit(func):
    def wrapper(*args, **kwargs):
        start_time = ()
        result = func(*args, **kwargs)
        end_time = ()
        print(f"{func.__name__} Function execution time: {end_time - start_time} Second")
        return result
    return wrapper

@timeit
def add_numbers(*args):
    return sum(args)

@timeit
def show_info(**kwargs):
    for key, value in ():
        print(f"{key}: {value}")

In this example, timeit is a decorator function, and its internal function wrapper uses * args and **kwargs to receive any number of parameters, and then passes these parameters to the original function func,Whether the add_numbers function receives an uncertain number of positional parameters or the show_info function receives an uncertain number of keyword parameters, it can be correctly received and passed by the wrapper function., and can also record the execution time of the function. For example, when we call add_numbers(1, 2, 3, 4, 5), we will first record the start time, execute the add_numbers function to calculate the sum, then record the end time, print out the function execution time, and finally return the sum; calling show_info(name="Xiaoming", age=20) is similar, first record the time, print the information, and then return None (because the show_info function does not return the value).

If the internal functions in the decorator do not use * args and *kwargs, but write fixed parameters dead, then this decorator can only be used for functions of specific parameters and types, and the flexibility will be greatly reduced. For example, if you write the wrapper function as def wrapper(a, b), it can only decorate the function that receives two positional parameters. If it is used to decorate a function with uncertain parameters such as add_numbers(args), an error will be reported, indicating that the number of parameters does not match.

Therefore, args and **kwargs are like two "bridges" in the decorator, allowing the decorator to seamlessly connect functions with various parameters, greatly expanding the application scope of the decorator and making your code more reusable. Whether it is simple function enhancement or complex framework development, they are inseparable from them. If you master the skills of using args and **kwargs in the decorator, you will be more at ease in the world of Python programming!

Summarize

This is the article about Python magic parameters args and kwargs. For more related Python magic parameters args and kwargs, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!