python functions args kwargs

Functions in Python

Learning objectives

By the end of this pill you will be able to:

  • define a function with def;
  • distinguish between positional and keyword parameters;
  • use optional parameters (default values);
  • handle a variable number of arguments (*args and **kwargs).

Basic definition

A function is a reusable block of code that performs a specific action. In Python it is defined with the keyword def, followed by the name, parentheses and a colon. The function body must be indented.

def greet(name):
    """This function prints a greeting."""
    message = f"Hello, {name}!"
    return message

# Function call
result = greet("Mario")
print(result)  # Hello, Mario!

Positional and keyword parameters

When calling a function you can pass arguments in two ways:

  • Positional: order matters. The first value goes to the first parameter, the second to the second, etc.
  • Keyword: you specify the parameter name. Order no longer matters.
def describe(animal, sound):
    print(f"The {animal} goes {sound}")

# Positional (correct order)
describe("dog", "woof")

# Keyword (order irrelevant)
describe(sound="meow", animal="cat")

# Mixed (positional must come before keyword!)
describe("cow", sound="moo")

Optional parameters (defaults)

You can assign a default value to a parameter. If the caller does not supply that value, the default is used. Parameters with defaults must always be defined after those without.

# 'exponent' is optional, default = 2
def power(base, exponent=2):
    return base ** exponent

print(power(3))     # 3^2 = 9 (uses the default)
print(power(3, 3))  # 3^3 = 27 (overrides the default)

Note: Be careful with mutable default values (such as lists or dictionaries). They are created only once when the function is defined.

Variable number of arguments

Sometimes you don’t know in advance how many arguments will be passed. Python provides two powerful tools for this.

*args: tuple of positional arguments

The asterisk * before the parameter name collects all extra positional arguments into a tuple.

def sum_all(*numbers):
    # 'numbers' is a tuple: (10, 20, 30)
    total = 0
    for n in numbers:
        total += n
    return total

print(sum_all(10, 20, 30))  # 60

**kwargs: dictionary of keyword arguments

The double asterisk ** collects extra keyword arguments into a dictionary (Keyword ARGS).

def create_profile(name, **details):
    # 'details' is a dictionary: {'age': 18, 'city': 'Rome'}
    print(f"Profile of {name}:")
    for key, value in details.items():
        print(f" - {key}: {value}")

create_profile("Luca", age=18, city="Rome", sport="Football")

Argument unpacking

You can also do the reverse: if you have a list or tuple and want to pass its values as separate arguments, use *.

coordinates = (10, 20)

def draw_point(x, y):
    print(f"Drawing point at {x}, {y}")

# Unpacking: the tuple is 'expanded' into the two arguments
draw_point(*coordinates)

In brief: use optional parameters to simplify common calls, and *args/**kwargs to make your functions flexible and capable of handling unexpected input.