Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Function Arguments & Return Values

Understand how to pass arguments to Python functions and return values from them. Covers required, default, keyword, and variable-length arguments with hands-on examples.

Focus: function arguments and return values

Sponsored

Have you ever written a Python function that felt rigid or confusing to call? Maybe you passed the wrong number of arguments, got a cryptic TypeError, or struggled to send a result back to the caller. These problems are exactly what understanding function arguments and return values solves — they give you the power to write flexible, reusable, and predictable functions that communicate cleanly with the rest of your code.

The problem this lesson solves

Without a solid grasp of function arguments and return values, your code can quickly become a tangled mess of global variables, duplicated logic, and hard-to-debug errors. You might find yourself writing functions that:

  • Accept parameters in a confusing order, making calls error-prone.
  • Use too few or too many arguments, forcing ugly workarounds.
  • Fail to return results at all, leaving callers guessing what happened.

Consider a function that calculates a discount. Without proper arguments, you might hardcode the price and discount rate, making the function useless for other scenarios. Return values are equally important — a function that prints a result instead of returning it cannot be used in further calculations or stored in variables. This lesson equips you to avoid these pitfalls by mastering the formal parameters and return mechanisms Python provides.

Core concept / mental model

Think of a function as a machine or a vending machine.

Analogy: The Vending Machine

  • Arguments are the coins or selections you insert. They are the inputs the machine (function) needs to operate.
  • Parameters are the slots where those coins go — the names inside the function definition that hold the values you pass.
  • Return value is the item that comes out of the machine. It's the output the machine produces after processing the inputs.

A vending machine doesn't work if you insert the wrong number of coins, or if you put coins in the wrong slots. Similarly, Python functions expect specific arguments in a defined order.

Definitions

  • Parameter: The variable name listed inside the parentheses in the function definition. Example: def greet(name):name is a parameter.
  • Argument: The actual value you pass to the function when calling it. Example: greet("Alice")"Alice" is an argument.
  • Return value: The value a function sends back to the caller using the return keyword. If no return is specified, the function returns None.

This simple model explains all the argument types you'll meet, from required to optional.

How it works step by step

Let's walk through the four main argument categories in Python, ordered by how you'll typically encounter them.

Step 1: Required (positional) arguments

These are the most basic. The caller must provide exactly the number of arguments the function defines, and their order matters.

def describe_pet(animal, name):
    print(f"{name} is a {animal}")

describe_pet("cat", "Whiskers")  # Works: Whiskers is a cat
describe_pet("Whiskers", "cat")  # Wrong order: cat is a Whiskers
# describe_pet("cat")  # TypeError: missing 1 required positional argument

The order of arguments maps to the order of parameters. This is why choosing good parameter names is essential.

Step 2: Default arguments

Default arguments make certain parameters optional. If the caller doesn't provide a value, the function uses the default.

def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

print(greet("Alice"))         # Hello, Alice!
print(greet("Bob", "Hi"))     # Hi, Bob!

Pro tip: Default arguments are evaluated only once, at function definition time. Avoid mutable defaults like def add_item(item, list=[]): — use None and create a new list inside.

Step 3: Keyword arguments

Keyword arguments let you pass arguments by name, ignoring the order. This is especially useful when a function has many parameters.

def create_profile(username, age, country):
    print(f"User: {username}, Age: {age}, From: {country}")

# Positional
create_profile("alice99", 28, "USA")

# Keyword (any order)
create_profile(country="Canada", username="bob_dev", age=35)

You can mix positional and keyword arguments, but all positional arguments must come first.

Step 4: Variable-length arguments (*args and **kwargs)

Sometimes you don't know how many arguments a function will receive. Use *args for an arbitrary number of positional arguments and **kwargs for keyword arguments.

def log_messages(level, *messages):
    for msg in messages:
        print(f"[{level}] {msg}")

log_messages("INFO", "Server started", "Connection established", "Ready")
# Output:
# [INFO] Server started
# [INFO] Connection established
# [INFO] Ready

def build_query(**filters):
    return " AND ".join(f"{k}={v}" for k, v in filters.items())

print(build_query(city="Paris", status="active"))
# Output: city=Paris AND status=active

Hands-on walkthrough

Now it's your turn. Let's build a function that calculates the area of different shapes using various argument types.

Example 1: Simple area calculator with default arguments

def area_calculator(shape, radius=None, length=None, width=None):
    """Calculate area for circle, square, or rectangle."""
    if shape == "circle":
        if radius is not None:
            return 3.14 * radius * radius
    elif shape == "square":
        if length is not None:
            return length * length
    elif shape == "rectangle":
        if length is not None and width is not None:
            return length * width
    return None  # invalid

print(area_calculator("circle", radius=5))   # 78.5
print(area_calculator("square", length=4))   # 16
print(area_calculator("rectangle", length=3, width=7))  # 21

Example 2: Using *args for summing arbitrary numbers

def flexible_sum(operation, *numbers):
    """Sum all provided numbers."""
    if operation == "add":
        return sum(numbers)
    elif operation == "multiply":
        result = 1
        for n in numbers:
            result *= n
        return result
    else:
        return "Unsupported operation"

print(flexible_sum("add", 1, 2, 3, 4))       # 10
print(flexible_sum("multiply", 2, 3, 4))     # 24

Example 3: Mixing keyword and variable-length arguments

def create_event(name, date, **details):
    print(f"Event: {name} on {date}")
    for key, value in details.items():
        print(f"  {key}: {value}")

create_event("Python Webinar", "2025-03-15",
             host="Dr. Smith",
             duration="2 hours",
             platform="Zoom")
# Output:
# Event: Python Webinar on 2025-03-15
#   host: Dr. Smith
#   duration: 2 hours
#   platform: Zoom

Compare options / when to choose what

Argument Type Use Case Example Header
Required (positional) Simple functions with a small, fixed number of inputs def add(a, b):
Default When a value is usually the same but can change def connect(host, port=80):
Keyword Functions with many parameters; improves readability def plot(x, y, color="red", style="solid"):
*args Variable number of positional inputs (e.g., summing numbers) def average(*nums):
**kwargs Extending functions with optional configuration def send_email(to, **options):

Best practice: Prefer keyword arguments for clarity when a function has more than 2–3 parameters. Use *args only when you genuinely don't know the count (e.g., mathematical operations). Avoid overusing **kwargs as it can hide required parameters.

Troubleshooting & edge cases

Common mistake 1: Mutable default arguments

def add_item(item, list=[]):  # Bug!
    list.append(item)
    return list

print(add_item("a"))  # ['a']
print(add_item("b"))  # ['a', 'b'] — shared list across calls!

Fix: Use None and create a new list inside the function.

Common mistake 2: Forgetting the return statement

def square(x):
    result = x * x  # No return statement

print(square(5))  # Outputs: None

Fix: Always include return to send a value back, or be explicit about using None for side-effect-only functions.

Common mistake 3: Wrong argument order with mixed types

def report(name, age, country="Unknown"):
    print(f"{name}, {age}, from {country}")

report("Alice", 30)            # Works
report(30, "Alice")            # Wrong order — Alice's name swapped with age

Fix: Use keyword arguments for clarity when order could be confusing.

Edge case: Returning multiple values

Functions can return multiple values as a tuple, which you can unpack.

def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([3, 1, 7, 2, 9])
print(f"Low: {low}, High: {high}")  # Low: 1, High: 9

What you learned & what's next

You now understand the full spectrum of function arguments and return values in Python. You can confidently:

  • Explain how required, default, keyword, and variable-length arguments work.
  • Apply these argument types to build flexible functions.
  • Connect argument patterns to real-world code readability and maintainability.

You've seen how arguments influence how functions are called and how return values enable clean data flow. This foundation is critical because in the next lesson, you'll explore function scope and global/local variables — where understanding how data moves in and out of functions becomes essential.

Practice what you've learned by writing a function that accepts a list of numbers via *args and returns the average, the minimum, and the maximum. Try calling it with different numbers and observe how it behaves with no arguments (hint: handle that edge case!).

Practice recap

Write a Python function called analyze_numbers that accepts any number of numeric arguments via *args. It should return a dictionary with keys 'sum', 'average', 'min', and 'max'. Handle the edge case where no numbers are passed by returning None instead of crashing. Test it with analyze_numbers(5, 10, 15) and analyze_numbers().

Common mistakes

  • Using mutable default arguments like def func(lst=[]) — the list is shared across all calls. Fix by using None and creating a new list inside.
  • Forgetting the return statement — the function returns None silently, causing bugs downstream.
  • Confusing parameter order when mixing positional and keyword arguments — all positional must come before keyword arguments.
  • Assuming args captures everything including keyword arguments — args only captures extra positional arguments, not named ones.
  • Expecting return to print output — return sends a value to the caller, it doesn't display anything on its own.

Variations

  1. Use args and kwargs together to accept arbitrary positional and keyword arguments (e.g., def wrapper(args, kwargs):) — common in decorators.
  2. Type hints (def greet(name: str) -> str:) improve code clarity and enable static type checking without changing runtime behavior.
  3. Lambda functions can use arguments implicitly via lambda x, y: x + y, but they are limited to single expressions and cannot use statements.

Real-world use cases

  • Building a logging function that accepts variable messages via *args and optional severity via **kwargs.
  • Creating a data processing pipeline that takes required column names and optional filters using keyword arguments.
  • Writing a mathematical utility that computes statistics with *args for flexible input counts.

Key takeaways

  • Required arguments must be provided in order; default arguments make some parameters optional.
  • Keyword arguments improve readability and can be passed in any order after positional arguments.
  • Use *args for a variable number of positional arguments and **kwargs for named options.
  • Always include a return statement if the function needs to produce a result; otherwise it returns None.
  • Avoid mutable default arguments — use None and check inside the function body.
  • Returning multiple values is done via a tuple, which you can unpack directly in the caller.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.