Ora

How to Use Asterisk in Python?

Published in Python Operators 4 mins read

In Python, the asterisk (*) and double asterisk (**) are versatile operators primarily used for handling a variable number of arguments in function definitions, unpacking iterables, and merging collections. Understanding their distinct applications can significantly enhance your Python programming efficiency and flexibility.

These operators serve two main purposes: packing (gathering multiple arguments into a single object) and unpacking (spreading elements from an iterable or dictionary into individual arguments).

The Single Asterisk (*)

The single asterisk (*) is a powerful tool with several key applications in Python.

1. Packing Positional Arguments (*args)

When used in a function definition, *args allows a function to accept a variable number of non-keyword (positional) arguments. All the positional arguments passed to the function are automatically gathered and converted into a tuple. This makes it ideal for functions where you don't know in advance how many inputs they might receive.

Example:

def sum_all_numbers(*args):
    """Calculates the sum of an arbitrary number of numbers."""
    total = 0
    for num in args:
        total += num
    return total

print(sum_all_numbers(1, 2, 3))         # Output: 6
print(sum_all_numbers(10, 20, 30, 40))  # Output: 100

In this example, *args collects 1, 2, 3 into the tuple (1, 2, 3) and 10, 20, 30, 40 into (10, 20, 30, 40).

2. Unpacking Iterables

The * operator can unpack elements from iterables (like lists, tuples, or sets) into individual arguments when calling a function, or to combine iterables.

  • In Function Calls: It "unpacks" the elements of an iterable, treating each element as a separate positional argument.

    Example:

    def greet(first, second, third):
        print(f"Hello {first}, {second}, and {third}!")
    
    names = ["Alice", "Bob", "Charlie"]
    greet(*names) # Unpacks names into "Alice", "Bob", "Charlie"
    # Output: Hello Alice, Bob, and Charlie!
  • For Merging/Copying Iterables: This is useful for creating new lists or tuples by combining existing ones.

    Example:

    list1 = [1, 2]
    list2 = [3, 4]
    combined_list = [*list1, 0, *list2]
    print(combined_list) # Output: [1, 2, 0, 3, 4]
    
    original_tuple = (10, 20, 30)
    copied_tuple = (*original_tuple,)
    print(copied_tuple) # Output: (10, 20, 30)

3. Enforcing Keyword-Only Arguments

When used alone in a function signature, * indicates that all subsequent parameters must be passed as keyword arguments, not positional arguments. This enhances code clarity and prevents accidental misuse of arguments.

Example:

def create_user(name, *, age, city):
    """Creates a user with mandatory keyword-only arguments for age and city."""
    print(f"User: {name}, Age: {age}, City: {city}")

create_user("John Doe", age=30, city="New York")
# Output: User: John Doe, Age: 30, City: New York

# create_user("Jane Doe", 25, "London") # This would raise a TypeError

The Double Asterisk (**)

The double asterisk (**) operator works similarly to the single asterisk but is specifically designed for keyword-value pairs.

1. Packing Keyword Arguments (**kwargs)

In a function definition, **kwargs allows a function to accept a variable number of keyword arguments. All keyword arguments passed to the function are automatically gathered and converted into a dictionary, where the argument names become keys and their values become dictionary values.

Example:

def display_profile(**kwargs):
    """Displays user profile details."""
    print("--- User Profile ---")
    for key, value in kwargs.items():
        print(f"{key.replace('_', ' ').title()}: {value}")

display_profile(name="Alice", age=28, occupation="Engineer")
# Output:
# --- User Profile ---
# Name: Alice
# Age: 28
# Occupation: Engineer

Here, **kwargs collects name="Alice", age=28, occupation="Engineer" into the dictionary {'name': 'Alice', 'age': 28, 'occupation': 'Engineer'}.

2. Unpacking Dictionaries

The ** operator can unpack key-value pairs from a dictionary, treating each pair as a separate keyword argument when calling a function, or for merging dictionaries.

  • In Function Calls: It "unpacks" the key-value pairs of a dictionary into individual keyword arguments.

    Example:

    def configure_settings(theme="dark", font_size=12, notifications=True):
        print(f"Theme: {theme}, Font Size: {font_size}, Notifications: {notifications}")
    
    user_preferences = {"font_size": 14, "theme": "light"}
    configure_settings(**user_preferences)
    # Output: Theme: light, Font Size: 14, Notifications: True
  • For Merging/Copying Dictionaries: This is a concise way to create new dictionaries by combining existing ones, with later dictionaries overwriting duplicate keys from earlier ones. (Available from Python 3.5 onwards).

    Example:

    default_config = {"host": "localhost", "port": 8080, "timeout": 30}
    user_overrides = {"port": 9000, "timeout": 60}
    
    final_config = {**default_config, **user_overrides, "log_level": "INFO"}
    print(final_config)
    # Output: {'host': 'localhost', 'port': 9000, 'timeout': 60, 'log_level': 'INFO'}

Summary Table: Asterisk Usage in Python

Feature Single Asterisk (*) Double Asterisk (**)
Primary Purpose Variable positional arguments, iterable unpacking Variable keyword arguments, dictionary unpacking
Collects Arguments Into a tuple Into a dictionary
Function Definition *args to accept any number of positional arguments **kwargs to accept any number of keyword arguments
Function Call *iterable to unpack elements as positional arguments **dictionary to unpack items as keyword arguments
Other Uses Enforcing keyword-only arguments, merging iterables Merging dictionaries (Python 3.5+), dictionary copying

For further reading, you can refer to the official Python documentation on arbitrary argument lists.

Understanding and correctly applying the single and double asterisks can lead to more flexible, readable, and Pythonic code, making your functions adaptable to various input scenarios.