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.