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

In Python, the * (single star) and ** (double star) symbols are used in function definitions and calls to handle variable numbers of arguments. Here’s a breakdown of their roles:

1. In Function Definitions

* (Single Star)

  • Captures positional arguments into a tuple.
  def func(*args):
      print(args)  # args is a tuple of positional arguments

  func(1, 2, 3)  # Output: (1, 2, 3)
  • Enforces keyword-only arguments when used in parameter lists:
  def func(a, b, *, c, d):
      # Parameters after * (c, d) must be keyword-only
      pass

  func(1, 2, c=3, d=4)  # Valid
  func(1, 2, 3, 4)       # Error: c and d must be keyword arguments

** (Double Star)

  • Captures keyword arguments into a dictionary:
  def func(**kwargs):
      print(kwargs)  # kwargs is a dict of keyword arguments

  func(a=1, b=2)  # Output: {'a': 1, 'b': 2}

2. In Function Calls

* (Unpack Iterables)

  • Unpacks iterables (e.g., lists, tuples) into positional arguments:
  def func(a, b, c):
      print(a, b, c)

  args = [1, 2, 3]
  func(*args)  # Equivalent to func(1, 2, 3)

** (Unpack Dictionaries)

  • Unpacks dictionaries into keyword arguments:
  def func(a, b, c):
      print(a, b, c)

  kwargs = {'a': 1, 'b': 2, 'c': 3}
  func(**kwargs)  # Equivalent to func(a=1, b=2, c=3)

3. Combined Usage

  • *args and **kwargs together:
  def func(*args, **kwargs):
      print(f"Positional: {args}")
      print(f"Keyword: {kwargs}")

  func(1, 2, a=3, b=4)
  # Output:
  # Positional: (1, 2)
  # Keyword: {'a': 3, 'b': 4}
  • Mixed parameters (positional, keyword-only, etc.):
  def func(a, b=0, *args, c, d=0, **kwargs):
      # a: positional (required)
      # b: positional (optional)
      # args: extra positional arguments
      # c: keyword-only (required)
      # d: keyword-only (optional)
      # kwargs: extra keyword arguments
      pass

Key Notes

  • Order of parameters: Follow the sequence:
    (positional_args, *args, keyword-only_args, **kwargs).
  • Unpacking in calls: Use */** to pass iterables/dictionaries as arguments.
  • Keyword-only enforcement: Place * in the parameter list to require certain arguments to be passed by keyword.

Examples

Enforcing Keyword-Only Arguments

def calculate(a, b, *, operation="add"):
    if operation == "add":
        return a + b
    elif operation == "subtract":
        return a - b

calculate(2, 3)                     # Uses default operation="add"
calculate(5, 3, operation="subtract")  # Explicit keyword argument

Unpacking Nested Structures

data = {"a": 1, "b": 2, "c": 3}
nested = [data, {"d": 4}]

for item in nested:
    func(**item)  # Calls func(a=1, b=2, c=3) then func(d=4)

Summary

SymbolContextPurpose
*DefinitionCaptures extra positional arguments into a tuple (*args).
*DefinitionEnforces keyword-only parameters after *.
*CallUnpacks iterables into positional arguments.
**DefinitionCaptures extra keyword arguments into a dictionary (**kwargs).
**CallUnpacks dictionaries into keyword arguments.

These symbols provide flexibility for handling dynamic arguments and enforcing parameter rules in Python functions.

Leave a Reply

Your email address will not be published. Required fields are marked *