Python return Statement Explained Clearly

Updated on: May 21, 2026
Reading time: 9 minutes
Como usar o comando return em funções Python

The Python return statement is one of the most important concepts to understand when you start writing real functions. Beginners often learn print() first, so it is natural to think that showing a value on the screen is the same as giving that value back to the program. It is not. A printed value is only displayed. A returned value can be stored, tested, passed to another function, reused, transformed, or sent back from an API.

This English version is adapted for developers who want a practical explanation, not a literal translation. You will learn what return does, why it stops a function, how it differs from print(), how to return multiple values, why functions sometimes return None, and how to use return statements to write cleaner, testable Python code. If you are still learning the basics, start with this Python beginner guide and this guide to functions in Python.

What Does return Do in Python?

In Python, return sends a value from inside a function back to the code that called that function. A function can receive input through parameters, process that input, and return an output. That output becomes available to the rest of your program. This is the difference between a function that only performs an action and a function that produces a reusable result.

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

result = add(10, 5)
print(result)      # 15
print(result * 2)  # 30

The function add() does not print anything by itself. It returns the calculated value. Because the result is returned, the caller can store it in a variable and use it later. That makes the function reusable in scripts, applications, tests, APIs, data pipelines, and other functions.

The official Python documentation explains return as the statement that leaves the current function call and optionally passes back an expression value. You can read the formal definition in the Python language reference.

return Stops the Function Immediately

A return statement does two things. First, it sends a value back to the caller. Second, it exits the function immediately. Any code placed after a return statement in the same execution path will not run. This is why return is also used to stop a function early when a condition has already been handled.

def check_age(age):
    if age < 18:
        return "Access denied"

    return "Access granted"

print(check_age(16))
print(check_age(25))

When age is less than 18, Python returns "Access denied" and leaves the function. It does not continue to the final line. This early-exit pattern keeps code simple because you can handle invalid cases first and let the normal path remain easy to read. If conditional logic still feels confusing, review this guide on programming logic with Python.

return vs print: The Key Difference

The most common beginner mistake is confusing return with print(). The print() function displays information in the terminal. The return statement gives information back to the caller. A value printed to the screen is not automatically available for calculations, comparisons, tests, or other functions.

def add_with_print(a, b):
    print(a + b)


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

x = add_with_print(5, 5)
y = add_with_return(5, 5)

print(x)      # None
print(y)      # 10
print(y * 2)  # 20

The first function displays 10, but it does not return 10. Because no explicit return value exists, Python returns None. The second function returns the value, so it can be multiplied, stored, or passed into another function. Understanding None in Python is essential because many confusing bugs come from expecting a function to return data when it only prints data.

Functions Return None by Default

Every Python function returns something. If you do not write a return statement, Python returns None automatically. This is normal for functions that only perform an action, such as writing a file, sending a notification, or printing a message. But it becomes a bug when you expected a usable value.

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

result = greet("Ana")
print(result)  # None

The variable message exists only inside the function. Because the function never returns it, the caller receives None. To make the message available outside the function, return it:

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

result = greet("Ana")
print(result)

This is where variable scope matters. Values created inside a function do not automatically become available everywhere else. If that topic is new, read this explanation of variable scope in Python.

Returning Multiple Values

Python makes it easy to return multiple values. When you separate values with commas after return, Python returns them as a tuple. You can then unpack that tuple into separate variables. This is useful when a function naturally produces more than one result, such as minimum, maximum, and average values.

def get_stats(numbers):
    minimum = min(numbers)
    maximum = max(numbers)
    average = sum(numbers) / len(numbers)
    return minimum, maximum, average

low, high, avg = get_stats([10, 20, 30, 40])

print(low)
print(high)
print(avg)

This syntax is concise, but use it carefully. If a function returns too many unrelated values, a dictionary, data class, or object may be clearer. For small related groups of values, tuple unpacking is clean and idiomatic. To understand the structure behind this behavior, review tuples in Python and Python lists.

Returning Early with Guard Clauses

Return statements are often used as guard clauses. A guard clause checks for an invalid or special case at the beginning of a function and returns immediately. This avoids deep nesting and makes the main logic easier to read. Instead of wrapping everything inside large if blocks, you handle the edge cases first.

def calculate_discount(price, percentage):
    if price <= 0:
        return 0

    if percentage <= 0:
        return price

    discount = price * (percentage / 100)
    return price - discount

This function is easy to scan. Invalid prices return 0. Invalid discounts return the original price. The normal calculation happens only after those cases are handled. This pattern appears frequently in APIs, form validation, automation scripts, and data processing functions. It is also a useful habit for writing clean code, as discussed in these Python best practices.

Returning Different Data Types

Python lets you return any object: strings, numbers, lists, dictionaries, tuples, booleans, functions, class instances, or None. This flexibility is powerful, but it can also make code confusing when a function returns inconsistent types. For example, a function that sometimes returns a list and sometimes returns a string error message can be difficult to use safely.

# Harder to work with

def find_users(active_only=True):
    if active_only:
        return ["Ana", "Bruno"]
    return "No filter applied"

In most cases, prefer consistent return types. A function that returns a list should return an empty list when there are no results, not a string. A function that returns a dictionary should document its keys clearly. Consistency makes code easier to test and reduces surprise. If type behavior is still unclear, this guide to Python data types is a useful next step.

Using return with Boolean Logic

A function can return the result of a comparison directly. This is useful for validation functions because comparisons already produce True or False. You do not need to write a full if statement when the expression itself already answers the question.

def is_adult(age):
    return age >= 18

print(is_adult(16))  # False
print(is_adult(21))  # True

This style is short and readable when the condition is simple. If the condition becomes complex, assign intermediate names or use multiple guard clauses. Compact code is not always better. The goal is clarity.

Returning Functions from Functions

Because functions are objects in Python, you can return a function from another function. This idea appears in decorators, closures, factories, and advanced configuration patterns. You may not need this every day as a beginner, but recognizing it helps you understand more professional Python code later.

def make_multiplier(factor):
    def multiply(number):
        return number * factor

    return multiply

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(10))
print(triple(10))

The function make_multiplier() returns another function. The returned function remembers the value of factor. This concept is closely related to Python decorators, where one function often returns a wrapper function.

return Inside Loops

A return statement inside a loop exits the entire function, not just the loop. This can be exactly what you want when searching for the first match. It can also be a bug when you accidentally return during the first iteration. Always check indentation carefully when a function returns earlier than expected.

def find_first_even(numbers):
    for number in numbers:
        if number % 2 == 0:
            return number

    return None

print(find_first_even([1, 3, 5, 8, 9]))

This function stops as soon as it finds the first even number. If no even number exists, it returns None after the loop finishes. That final return matters because it makes the “not found” case explicit. If loops are still a weak point, review the basics of loops in Python.

Adding Type Hints to Return Values

Type hints make return values easier to understand. They do not change runtime behavior by themselves, but they help editors, static analysis tools, and other developers understand what a function is expected to return. This is especially useful in larger projects where functions are reused across multiple files.

def format_username(name: str) -> str:
    return name.strip().lower()


def divide(a: float, b: float) -> float | None:
    if b == 0:
        return None
    return a / b

The arrow syntax indicates the expected return type. In the second function, float | None communicates that the function may return a number or None. This makes the function safer to use because the caller knows it must handle the zero-division case. For more examples, read this guide to Python type hints.

Common Mistakes with return

The first mistake is using print() when you need return. The second is forgetting a return statement and accidentally getting None. The third is returning too early inside a loop because of wrong indentation. The fourth is returning inconsistent data types. The fifth is writing code after a return statement and expecting it to run.

Another common mistake is assuming return belongs everywhere. Some functions are designed only to perform side effects, such as writing a file or logging a message. Those functions may not need a meaningful return value. The important part is being intentional. A function should either return useful data or clearly perform an action.

Best Practices for Clean Return Statements

Keep return values consistent. Use guard clauses to handle invalid input early. Avoid hiding too much logic inside a single return line when it harms readability. Document what your function returns, especially when returning dictionaries, tuples, or optional values. Prefer returning data over printing when you want code to be reusable and testable.

The PEP 8 style guide also recommends consistency when returning values. If a function returns a value in one branch, make sure other branches are clear as well. This avoids confusing functions where some paths return useful data and other paths accidentally return None.

Final Checklist

Use return when a function needs to give a value back to the caller. Remember that return exits the function immediately. Use print() only when you want to display information, not when you need reusable data. Return multiple values with commas when the values are closely related. Handle None intentionally. Use type hints and documentation when the return value is important for other parts of the project.

Once you understand return, your Python functions become more powerful. You stop writing scripts that only show output and start writing reusable building blocks. That is the difference between code that works once and code that can support real applications, tests, APIs, automation workflows, and larger projects.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Explicação prática de args e kwargs em funções Python
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Python *args and **kwargs Explained Clearly

    Learn how Python *args and **kwargs work, when to use them, how unpacking works, and how to avoid common mistakes

    Ler mais

    Tempo de leitura: 8 minutos
    19/05/2026
    Leitura de arquivos grandes em Python sem travar o sistema
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Read Giant Files in Python Without Freezing

    Learn how to read huge files in Python using line-by-line iteration, generators, chunksize, streaming JSON, compression, and encoding handling.

    Ler mais

    Tempo de leitura: 8 minutos
    19/05/2026
    Como converter código Python para C usando Cython
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Convert Python to C Code with Cython

    Learn how to speed up Python with Cython, static typing, compilation, benchmarks, best practices, and cases where Cython is not

    Ler mais

    Tempo de leitura: 8 minutos
    19/05/2026
    Herança múltipla em Python sem causar problemas no código
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    Multiple Inheritance in Python Without Bugs

    Learn Python multiple inheritance, MRO, super(), mixins, and the Diamond Problem with clean patterns that avoid fragile class hierarchies.

    Ler mais

    Tempo de leitura: 8 minutos
    19/05/2026
    Uso de map e filter para agilizar código Python
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    How map and filter Speed Up Your Python Code

    Learn how map and filter speed up your Python code using lazy evaluation and functional programming. This guide covers syntax,

    Ler mais

    Tempo de leitura: 8 minutos
    14/05/2026
    Comparação entre list comprehension e generator expression em Python
    Fundamentals
    Foto de perfil de Leandro Hirt da Academify

    List Comprehension vs Generator Expression: Which to Use in Python?

    Learn when to use list comprehension vs generator expression in Python. This guide covers memory usage, lazy evaluation, performance benchmarks,

    Ler mais

    Tempo de leitura: 9 minutos
    14/05/2026