Python Variable-Length Keyword Arguments (**kwargs): How to Accept Any Number of Optional Arguments

When defining a function, there are cases where you want to accept an arbitrary number of “optional settings” or “additional attributes” apart from the mandatory arguments. While *args (introduced in the previous article) receives “positional arguments” as a tuple, if you want to receive a set of argument names (keys) and values as a dictionary, you use **kwargs.

This article explains the basic usage of **kwargs and the important rules when using it in combination with *args.


目次

What are Variable-Length Keyword Arguments (**kwargs)?

If you add two asterisks (**) before an argument name in a function definition, that argument receives “all remaining keyword arguments” passed during the call as a dictionary (dict). By convention, the variable name kwargs (short for keyword arguments) is used, but you can use any name like **options or **attributes.

Basic Usage

As a specific example, let’s consider a function to create a user profile. The name and email address are mandatory, but other attributes (age, job, address, etc.) vary by user, so we receive them flexibly with **kwargs.

def create_user_profile(username, email, **attributes):
    """
    Accept mandatory info and arbitrary additional attributes to display a profile.
    """
    print(f"--- User: {username} ---")
    print(f"Email: {email}")
    
    # attributes is received as a dictionary
    print(f"Number of additional attributes: {len(attributes)}")
    print(f"Type: {type(attributes)}")
    
    # Since it's a dict, we can loop with .items()
    for key, value in attributes.items():
        print(f"  {key}: {value}")

# --- Calling the function ---

# 1. Mandatory arguments only
create_user_profile("Suzuki", "suzuki@example.com")

print("\n")

# 2. Mandatory args + arbitrary keyword args
create_user_profile(
    "Tanaka", 
    "tanaka@example.com", 
    age=30, 
    job="Engineer", 
    city="Tokyo"
)

Output:

--- User: Suzuki ---
Email: suzuki@example.com
Number of additional attributes: 0
Type: <class 'dict'>


--- User: Tanaka ---
Email: tanaka@example.com
Number of additional attributes: 3
Type: <class 'dict'>
  age: 30
  job: Engineer
  city: Tokyo

Arguments like age=30 are treated inside the create_user_profile function as a dictionary: {'age': 30, 'job': 'Engineer', 'city': 'Tokyo'}.


Combining Positional, *args, and **kwargs

In Python functions, you can combine all three types of arguments. However, there is a strict rule regarding the order of definition. You must write them in the following order:

  1. Positional Arguments (Normal arguments)
  2. *args (Variable-length positional arguments)
  3. **kwargs (Variable-length keyword arguments)

Syntax:

def function_name(positional_args, *args, **kwargs):
    # Process

Specific Example

Here is an example of a log output function that receives severity (positional), message content (variable-length positional), and metadata (variable-length keyword) all at once.

def write_system_log(severity, *messages, **metadata):
    print(f"[{severity}]")
    
    # Process messages (tuple)
    for msg in messages:
        print(f"  Message: {msg}")
        
    # Process metadata (dict)
    if metadata:
        print("  Metadata:")
        for key, val in metadata.items():
            print(f"    {key} = {val}")

# --- Calling ---
write_system_log(
    "ERROR",                # severity (positional)
    "Connection failed",    # *messages (1st)
    "Timeout occurred",     # *messages (2nd)
    user_id=101,            # **metadata
    timestamp="12:00:00"    # **metadata
)

Output:

[ERROR]
  Message: Connection failed
  Message: Timeout occurred
  Metadata:
    user_id = 101
    timestamp = 12:00:00

If you do not follow this order, a SyntaxError will occur.


Unpacking Dictionaries to Pass

If you want to pass data you already hold as a dictionary to a function as keyword arguments, use ** at the calling side to unpack (expand) the dictionary.

# Dictionary data
user_info = {
    "age": 25,
    "job": "Designer",
    "city": "Osaka"
}

# Passing the dict as is causes an error (argument count mismatch or treated as positional)
# create_user_profile("Sato", "sato@example.com", user_info) 

# Add ** to unpack and pass
create_user_profile("Sato", "sato@example.com", **user_info)

This is treated exactly the same as specifying age=25, job="Designer", city="Osaka" individually.


Summary

  • Adding ** to an argument (e.g., **kwargs) allows you to accept an arbitrary number of keyword arguments as a dictionary.
  • The definition order is critical: def func(arg, *args, **kwargs):.
  • Adding ** to a dictionary at the calling side allows you to unpack it as keyword arguments and pass it to the function.
  • This feature is a very powerful tool when creating API wrapper functions or functions with many configuration options.
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次