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

    números inteiros sendo mostrados
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python Integers: Complete Beginner Guide

    Learn Python integers with arithmetic, division, conversions, large numbers, numeric bases, validation, range, bitwise operations, common mistakes, and practical examples.

    Ler mais

    Tempo de leitura: 5 minutos
    10/07/2026
    logo do Python com o texto input() no meio
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python input(): Complete Beginner Guide

    Learn Python input() with text, numbers, validation loops, conversions, menus, passwords, multiple values, error handling, and practical beginner projects.

    Ler mais

    Tempo de leitura: 4 minutos
    10/07/2026
    Logo do Python com emoji pensativo e a palavra PRINT sobre fundo azul
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python print(): Complete Beginner Guide

    Learn Python print() from basic text and variables to separators, line endings, f-strings, alignment, files, debugging, logging, and common mistakes.

    Ler mais

    Tempo de leitura: 4 minutos
    10/07/2026
    Ilustração que representa um algoritmo
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    What Is an Algorithm in Programming?

    Learn what an algorithm is in programming with everyday examples, pseudocode, flowcharts, Python implementations, efficiency, testing, and practice tips.

    Ler mais

    Tempo de leitura: 6 minutos
    10/07/2026
    Logo do Python com expressão pensativa e o texto range(), representando a função range no Python
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python range(): Complete Guide with Examples

    Learn Python range() with start, stop, step, negative values, loops, indexing patterns, performance, common mistakes, and practical beginner examples.

    Ler mais

    Tempo de leitura: 4 minutos
    10/07/2026
    texto 'operadores em Python' com os simbolos de operadores e o logo do Python à direita
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python Operators: Types and Practical Examples

    Learn Python operators with arithmetic, comparison, assignment, logical, membership, identity, bitwise, set, and conditional examples, plus precedence and common mistakes.

    Ler mais

    Tempo de leitura: 5 minutos
    10/07/2026