Explain Codes LogoExplain Codes Logo

What does ** (double star/asterisk) and * (star/asterisk) do for parameters?

python
argument-passing
function-definition
python-features
Nikita BarsukovbyNikita Barsukov·Mar 10, 2025
TLDR

In Python, * unpacks iterables into positional arguments, while ** unpacks dictionaries into keyword arguments for function invocation.

Give * a whirl:

def add(a, b): return a + b nums = [3, 5] # Like splitting a KitKat before eating print(add(*nums)) # Output: 8

Now, let ** take center stage:

def introduce(name, greeting): return f"{greeting}, {name}!" info = {'name': 'Alice', 'greeting': 'Hello'} # Unpacking those info like it's Christmas morning print(introduce(**info)) # Output: Hello, Alice!

Unleashing argument flexibility with *args and **kwargs

In function definition, *args slurps additional positional arguments into a tuple, and **kwargs sucks in additional keyword arguments into a dictionary. These argument packers allows for flexible parameter passing, making your functions incredibly adaptable.

Function with packed house:

def grand_gala_event(*attendees, **arrangements): print(f"Attendees: {attendees}") print(f"Arrangements: {arrangements}")

This is a party for everyone:

grand_gala_event('Alice', 'Bob', flowers='Roses', music='Jazz')

Outputs:

Attendees: ('Alice', 'Bob')
Arrangements: {'flowers': 'Roses', 'music': 'Jazz'}

Python 3+: Applauding keyword-only arguments

Python 3's feature of * in function parameters enforces keyword-only arguments after it. It's like Python intervening, "Hey, let's be explicit about which arguments we're talking about!".

Like putting a keeper at your castle gate:

def configure_system(*, operating_system, processor): pass # Medieval configuration logic here would be true magic.

So, you must knock it with names:

configure_system(operating_system='Linux', processor='ARM')

Python 3+: Enhanced iterable unpacking

With * in iterable assignment, collect all extra items that don't have their own dedicated variables. It's like your mum who ensures nobody gets left behind!

first, *rest = [1, 2, 3, 4] print(first) # Output: 1 print(rest) # Output: [2, 3, 4]

Preserved dictionary ordering from Python 3.6+

As of Python 3.6, dictionaries are well-behaved kids that remember the order of their elements. This behavior impacts the ordering of **kwargs.

Decorators: Unpacking superheroes with *args and **kwargs

*args and **kwargs are like Swiss army knives in decorators, helping you wrap any function or method regardless of their signature.

A simplistic decorator, just for kicks:

def my_decorator(func): def wrapper(*args, **kwargs): # Do some pre-processing, like shouting to the world that you're about to call a method! return func(*args, **kwargs) return wrapper

Best practices: Relishing *args and **kwargs

While *args and **kwargs wield immense power, with great power comes the responsibility to use these tools judiciously. Below are some pointers:

  • Choice of Names: args and kwargs are convention. They're the Pythonistas' sweetheart. Stick with them unless you really have to "paint the bike shed".
  • Selectivity: Resist the urge to go on a "one *args, one **kwargs, one function fits all" crusade. They're best employed when argument requirements are truly flexible.
  • Documentation: Be a sport, give your fellow devs a detailed account of your function, especially if it hosts a *args and **kwargs party inside.