backend / python core / 13_args_kwargs.md

args kwargs

3 interview angles 2 min read source

*args: Non-Keyword Variable-Length Arguments

  • Purpose: Allows a function to accept any number of positional arguments.
  • Syntax: A single asterisk (*) followed by a variable name (commonly args).
  • Behavior: All additional positional arguments passed to the function are collected into a tuple.

Example:

def print_numbers(*args):
    for number in args:
        print(number)

# Call the function with multiple arguments
print_numbers(1, 2, 3, 4, 5)

Output:

1
2
3
4
5

**kwargs: Keyword Variable-Length Arguments

  • Purpose: Allows a function to accept any number of keyword arguments.
  • Syntax: Two asterisks (**) followed by a variable name (commonly kwargs).
  • Behavior: All additional keyword arguments passed to the function are collected into a dictionary.

Example:

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

# Call the function with multiple keyword arguments
print_key_values(name="Alice", age=30, location="Wonderland")

Output:

name: Alice
age: 30
location: Wonderland

Using *args and **kwargs Together

You can use both *args and **kwargs in the same function. However, *args must appear before **kwargs in the function definition.

Example:

def mixed_arguments(arg1, *args, **kwargs):
    print(f"Fixed argument: {arg1}")
    print(f"Variable arguments (tuple): {args}")
    print(f"Keyword arguments (dict): {kwargs}")

# Call the function
mixed_arguments("Fixed", 1, 2, 3, name="Alice", age=30)

Output:

Fixed argument: Fixed
Variable arguments (tuple): (1, 2, 3)
Keyword arguments (dict): {'name': 'Alice', 'age': 30}

Key Points

  1. Flexibility: *args and **kwargs make functions flexible, accommodating varying numbers and types of arguments.
  2. Default Names: The names args and kwargs are conventions but can be changed (e.g., *variables, **options).
  3. Order Matters:
    • Positional arguments first.
    • Then *args.
    • Followed by keyword-only arguments or defaults.
    • Finally, **kwargs.

Example Order:

def example(positional, *args, keyword_only=None, **kwargs):
    pass
def display_args(*args, **kwargs):
    # Displaying all positional arguments (args)
    print("Positional arguments (args):")
    for arg in args:
        print(arg)
    
    # Displaying all keyword arguments (kwargs)
    print("\nKeyword arguments (kwargs):")
    for key, value in kwargs.items():
        print(f"{key}: {value}")

# Test the function with args and kwargs
display_args(1, 2, 3, name="Alice", age=25, city="New York")

Interview angle

  • “What do *args and **kwargs do?” - collect extra positional arguments into a tuple and extra keyword arguments into a dict. At the call site the same syntax unpacks a sequence or mapping into arguments.
  • “What are / and * in a signature?” - / marks the end of positional-only parameters, * marks the start of keyword-only ones. Keyword-only is the useful one for readable APIs: it forces callers to name boolean flags rather than passing a bare True.
  • “Why is a mutable default dangerous?” - defaults are evaluated once at definition, so a [] default is shared across every call. Use None and create inside. See tricky_questions/01_mutable_default_arguments.md.