Python Functions: Complete Beginner Guide

Published on: July 10, 2026
Reading time: 5 minutes
Definição e uso de funções com def em Python

Functions are reusable blocks of code that perform a defined task. They reduce repetition, give meaningful names to operations, separate responsibilities, and make programs easier to test and maintain.

This guide explains Python functions from the first def statement to parameters, return values, defaults, keyword arguments, scope, type hints, docstrings, flexible arguments, and practical design habits.

Why Functions Matter

Without functions, a program often repeats the same instructions in several places. A small change then requires editing every copy, and inconsistent versions create bugs.

price = 80
quantity = 3
discount = 0.10
subtotal = price * quantity
final_total = subtotal - subtotal * discount
print(final_total)

Turn the calculation into a reusable operation:

def calculate_total(price, quantity, discount):
    subtotal = price * quantity
    return subtotal - subtotal * discount


order_total = calculate_total(80, 3, 0.10)
print(order_total)

The function now describes the intention and can be called with different values. The official Python tutorial on functions is the primary language reference.

Define and Call a Function

def greet():
    print("Hello!")


greet()

def starts the definition, greet is the function name, parentheses contain parameters, and the indented block is the function body. Defining the function does not execute it; the call greet() does.

Parameters and Arguments

A parameter is a name in the function definition. An argument is the value supplied during a call.

def greet(name):
    print(f"Hello, {name}!")


greet("Maya")
greet("Leo")

Use multiple parameters when the task needs several inputs:

def rectangle_area(width, height):
    return width * height


print(rectangle_area(5, 3))

Return Values

return sends a value back to the caller. This is different from printing it.

def add(a, b):
    return a + b


result = add(4, 6)
print(result * 2)

A function without an explicit return statement returns None.

def show_message(message):
    print(message)


value = show_message("Done")
print(value)  # None

The Python None guide explains this special value and correct comparisons.

Return More Than One Value

Python can return several values as a tuple.

def minimum_and_maximum(values):
    return min(values), max(values)


lowest, highest = minimum_and_maximum([8, 3, 12, 5])
print(lowest)
print(highest)

For many related outputs, a dictionary, named tuple, or data class may be clearer than a long tuple.

Default Parameters

A default makes an argument optional.

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


print(greet("Maya"))
print(greet("Maya", "Welcome"))

Required parameters must appear before default parameters. Avoid mutable defaults such as lists.

# Problematic: the same list is reused
# def add_item(item, items=[]):
#     items.append(item)
#     return items


def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

Positional and Keyword Arguments

def create_user(name, age, active=True):
    return {"name": name, "age": age, "active": active}


user1 = create_user("Sam", 28)
user2 = create_user(age=31, name="Ava", active=False)

Keyword arguments make calls more readable and allow a different order. Do not place a positional argument after a keyword argument.

Keyword-Only Parameters

Add * to require keywords for selected parameters.

def calculate_price(subtotal, *, discount=0, tax=0):
    discounted = subtotal * (1 - discount)
    return discounted * (1 + tax)


final = calculate_price(100, discount=0.10, tax=0.05)
print(final)

This prevents confusing calls such as calculate_price(100, 0.10, 0.05), where the meaning of each number is unclear.

*args for Extra Positional Arguments

def average(*numbers):
    if not numbers:
        raise ValueError("At least one number is required")
    return sum(numbers) / len(numbers)


print(average(10, 20, 30))

numbers is a tuple containing all extra positional arguments. Use this flexibility only when the function genuinely accepts a variable number of similar values.

**kwargs for Extra Keyword Arguments

def build_profile(name, **details):
    profile = {"name": name}
    profile.update(details)
    return profile


profile = build_profile(
    "Ava",
    city="Lisbon",
    occupation="Developer",
)
print(profile)

details is a dictionary. The dedicated *args and **kwargs guide explains unpacking and common mistakes.

Unpack Arguments

def distance(x1, y1, x2, y2):
    return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5


points = (0, 0, 3, 4)
print(distance(*points))

For keyword arguments:

options = {"subtotal": 120, "discount": 0.15, "tax": 0.05}
print(calculate_price(**options))

Local and Global Scope

Names created inside a function are local unless explicitly declared otherwise.

tax_rate = 0.15


def calculate_tax(price):
    subtotal = price
    return subtotal * tax_rate


print(calculate_tax(100))
# print(subtotal)  # NameError outside the function

Prefer passing values as parameters and returning results instead of changing global state. Pure functions are easier to reason about and test.

Type Hints

Type hints document expected inputs and outputs and help editors and static-analysis tools.

def calculate_total(
    price: float,
    quantity: int,
    discount: float = 0.0,
) -> float:
    subtotal = price * quantity
    return subtotal * (1 - discount)

Python does not enforce these hints automatically at runtime. They improve communication and tooling. The official typing documentation covers the available types.

Docstrings

A docstring explains what a function does, its important parameters, return value, and exceptions.

def divide(a: float, b: float) -> float:
    """Return a divided by b.

    Raises:
        ValueError: If b is zero.
    """
    if b == 0:
        raise ValueError("b cannot be zero")
    return a / b

Access it through help(divide) or divide.__doc__. Continue with the Python docstrings guide.

Raise Exceptions for Invalid Inputs

A function should reject values that violate its contract.

def calculate_discount(price: float, percentage: float) -> float:
    if price < 0:
        raise ValueError("price cannot be negative")
    if not 0 <= percentage <= 1:
        raise ValueError("percentage must be between 0 and 1")
    return price * percentage

Do not silently replace invalid values unless that behavior is clearly part of the function’s design. The exception-handling guide explains how callers can respond.

Functions as Objects

Functions can be stored in variables, placed in collections, and passed to other functions.

def add(a, b):
    return a + b


def multiply(a, b):
    return a * b


operations = {
    "+": add,
    "*": multiply,
}

operator = "*"
print(operations[operator](4, 5))

This pattern is useful for terminal menus, event routing, and configurable behavior.

Lambda Expressions

A lambda creates a small anonymous function consisting of one expression.

products = [
    {"name": "Mouse", "price": 29.9},
    {"name": "Monitor", "price": 249.0},
    {"name": "Cable", "price": 8.5},
]

products.sort(key=lambda product: product["price"])
print(products)

Use def when logic needs a name, documentation, multiple statements, or error handling. The lambda functions guide compares both forms.

Recursion

A recursive function calls itself and must have a base case.

def factorial(number: int) -> int:
    if number < 0:
        raise ValueError("number cannot be negative")
    if number in {0, 1}:
        return 1
    return number * factorial(number - 1)

Loops are often simpler and avoid recursion-depth limits. Use recursion when the problem is naturally recursive, such as tree traversal. See the Python recursion guide.

Separate Input, Logic, and Output

Keep input() and print() at the application boundary. Core functions should receive values and return results.

def celsius_to_fahrenheit(celsius: float) -> float:
    return celsius * 9 / 5 + 32


try:
    celsius = float(input("Temperature in Celsius: "))
except ValueError:
    print("Enter a valid number.")
else:
    fahrenheit = celsius_to_fahrenheit(celsius)
    print(f"Temperature: {fahrenheit:.1f} °F")

The conversion function can be reused in a web page, API, test, or graphical interface without modification.

Test Functions

def test_calculate_total_without_discount():
    assert calculate_total(10, 3) == 30


def test_calculate_total_with_discount():
    assert calculate_total(100, 2, 0.10) == 180

Small, deterministic functions are easy to test. The Pytest beginner guide explains test discovery, assertions, and exceptions.

Practical Example: Shopping Cart

def line_total(price: float, quantity: int) -> float:
    if price < 0 or quantity < 0:
        raise ValueError("price and quantity cannot be negative")
    return price * quantity


def cart_total(items: list[dict]) -> float:
    return sum(
        line_total(item["price"], item["quantity"])
        for item in items
    )


def apply_coupon(total: float, percentage: float = 0.0) -> float:
    if not 0 <= percentage <= 1:
        raise ValueError("percentage must be between 0 and 1")
    return total * (1 - percentage)


cart = [
    {"name": "Keyboard", "price": 89.90, "quantity": 1},
    {"name": "Cable", "price": 8.50, "quantity": 2},
]

subtotal = cart_total(cart)
final_total = apply_coupon(subtotal, 0.10)
print(f"Final total: ${final_total:.2f}")

Each function has one responsibility and can be tested independently.

Common Mistakes

  • Printing a result when callers need it returned.
  • Creating functions with too many unrelated responsibilities.
  • Using vague names such as do_it() or process().
  • Changing global variables unnecessarily.
  • Using mutable default arguments.
  • Catching exceptions inside a function without a recovery plan.
  • Adding parameters only to avoid designing a clearer data structure.
  • Writing comments instead of extracting meaningful helper functions.

Frequently Asked Questions

What is the difference between a parameter and an argument?

A parameter is the name in the definition; an argument is the value supplied during a call.

Can a function return several values?

Yes. Python packages them into a tuple, which can be unpacked into multiple names.

When should I use a lambda?

Use it for a short expression passed immediately to another function, such as a sorting key. Prefer def for reusable or complex logic.

Are type hints required?

No, but they improve documentation, editor assistance, reviews, and static analysis.

How long should a function be?

There is no strict line limit. It should perform one coherent task and be understandable without excessive scrolling or hidden side effects.

Conclusion

Python functions transform repeated instructions into named, reusable operations. Start with clear parameters and return values, add defaults and keywords where they improve readability, validate the function’s contract, minimize global state, document important behavior, and write tests. These habits make programs easier to extend and debug.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Programador pensando enquanto analisa código em dois monitores
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Learn Programming from Scratch: Beginner Guide

    Learn programming from scratch with a practical roadmap covering logic, languages, tools, exercises, projects, debugging, Git, and consistent study habits.

    Ler mais

    Tempo de leitura: 6 minutos
    10/07/2026
    ícone de loop com o texto 'For' abaixo
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python for Loops: Complete Beginner Guide

    Learn Python for loops with sequences, range, enumerate, zip, dictionaries, nested loops, break, continue, comprehensions, and practical examples.

    Ler mais

    Tempo de leitura: 4 minutos
    10/07/2026
    Manipulação e formatação de strings em Python
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python Strings: Complete Beginner Guide

    Learn Python strings with creation, indexing, slicing, methods, formatting, Unicode, searching, validation, splitting, joining, and practical examples.

    Ler mais

    Tempo de leitura: 4 minutos
    10/07/2026
    código Python de uma tupla com o texto separado formando a frase "O que são tuplas?"
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python Tuples: Complete Beginner Guide

    Learn Python tuples with creation, packing, unpacking, indexing, immutability, methods, named records, function returns, and practical examples.

    Ler mais

    Tempo de leitura: 5 minutos
    10/07/2026
    símbolo de PI
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python Floats: Complete Beginner Guide

    Learn Python floats with decimal values, arithmetic, conversion, rounding, precision limits, comparisons, Decimal, math functions, and practical examples.

    Ler mais

    Tempo de leitura: 4 minutos
    10/07/2026
    notebook mostrando tela a teclado
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python Input and Output: Complete Guide

    Learn Python input and output with input(), print(), conversions, validation, formatting, files, command-line arguments, and practical interactive programs.

    Ler mais

    Tempo de leitura: 4 minutos
    10/07/2026