Previous | Tutorial index | Next

Tutorial 3: The return Statement – Returning Values from Functions

Learning Objectives

Overview

The return statement is the mechanism that allows a function to send a result back to its caller. Without return, a function is essentially a procedure that performs actions but produces no output that can be used elsewhere. In this tutorial, we explore how return works, what it means for a function to return None, how to return multiple values, and the critical difference between return and print. You'll learn to design functions that are useful building blocks by returning meaningful results.

1. The return Keyword – Exiting with a Value

1.1 Basic Use

return does two things:

  1. Terminates the function immediately: no further code in the function is executed.
  2. Sends back a value (or object) to the caller.
def square(x): return x * x # returns the square print("This will never run") result = square(5) # result gets 25 print(result) # 25

1.2 Returning Different Data Types

You can return any Python object – integers, floats, strings, booleans, lists, tuples, dictionaries, custom objects, or even functions.

def build_person(name, age): return {"name": name, "age": age} # returns a dictionary def get_evens(limit): return [i for i in range(limit) if i % 2 == 0] # returns a list def is_positive(num): return num > 0 # returns a boolean

2. Every Function Returns Something – The None Default

If a function does not explicitly use return, or if it uses return without a value, it implicitly returns None. None is a special object representing the absence of a value.

def do_nothing(): pass print(do_nothing()) # None def return_without_value(): return print(return_without_value()) # None

Important: None is commonly used as a sentinel to indicate that a function has no meaningful result (e.g., list.sort() returns None because it modifies the list in place).

3. Returning Multiple Values – Via Tuples

Python allows you to return multiple values by separating them with commas. They are automatically packed into a tuple. You can then unpack the tuple at the call site.

def swap(x, y): return y, x # returns a tuple (y, x) a, b = swap(10, 20) # unpacking: a=20, b=10 print(a, b) # 20 10 # Alternatively, you can capture the tuple directly result = swap(10, 20) print(result) # (20, 10)

This is a common and elegant way to return multiple pieces of data.

4. return vs. print – A Crucial Distinction

This is one of the most common beginner pitfalls.

Bad example – using print instead of return:

def add(a, b): print(a + b) # prints to console, but returns None result = add(3, 4) # prints 7, result becomes None print(result * 2) # TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'

Good example:

def add(a, b): return a + b # returns the sum result = add(3, 4) # result = 7 print(result * 2) # 14

Guideline: Use return for computing and producing data; use print only when you explicitly need to show something to the user (e.g., debugging, user prompts, reports). Keep your core logic return‑based.

5. Early Exit with return

You can use return to exit a function early, which is useful for conditional logic.

def absolute_value(x): if x < 0: return -x return x # if x >= 0, this runs

You can also have multiple return statements in different branches.

def classify_age(age): if age < 0: return "Invalid age" elif age < 18: return "Minor" elif age < 65: return "Adult" else: return "Senior"

6. Returning Complex Data Structures

Often you need to return a combination of values. Returning a dictionary or a custom object (which we haven't covered yet) can be very expressive.

def analyze_string(s): return { "length": len(s), "uppercase": s.upper(), "lowercase": s.lower(), "is_digit": s.isdigit() } info = analyze_string("Hello123") print(info["length"]) # 8

7. Returning Functions (Advanced)

Because functions are first‑class objects, you can return a function from another function. This is the basis for closures and decorators.

def make_multiplier(factor): def multiplier(x): return x * factor return multiplier times_3 = make_multiplier(3) print(times_3(10)) # 30

8. The return Statement and try/finally

When used inside a try block, a return will be executed, but the finally clause (if present) will run before the function actually returns.

def test(): try: return 1 finally: print("Cleaning up...") # this prints before the return print(test()) # prints "Cleaning up..." then 1

9. Common Mistakes

📝 Quiz – Check Your Understanding

  1. What does a function return if there is no return statement?

    Answer(B) `None`
  2. What is the output of the following code?

    def foo(x): return x * 2 print("Done") print(foo(3))
    Answer(B) `6` – the `print` is never executed.
  3. How do you return multiple values from a function?

    Answer(B) By returning a tuple.
  4. True or False: The print function returns a value that can be used in expressions.

    AnswerFalse – `print` returns `None`.
  5. What will this code print?

    def demo(): return print(demo())
    Answer(A) `None`
  6. Which of the following is a valid return statement?

    Answer(D) All of the above are valid.
  7. What is the difference between return and print?

    Answer(A) `return` sends data to the caller; `print` sends data to the console.
  8. Given def safe_divide(a, b): if b == 0: return None; return a / b, what does safe_divide(10, 0) return?

    Answer(B) `None`
  9. What does the following function return?

    def mystery(x): if x % 2 == 0: return "even" return "odd"
    Answer(C) `"even"` if even, `"odd"` otherwise.
  10. If a function returns a list, and you modify that list outside the function, does it affect the original list inside the function?

    Answer(A) Yes – the returned list is a reference to the same object.

💻 Exercises – Practice Makes Perfect

Exercise 1: Simple Return
Write a function celsius_to_fahrenheit(c) that converts Celsius to Fahrenheit and returns the result.

Sample Solution ```python def celsius_to_fahrenheit(c): return c * 9/5 + 32

print(celsius_to_fahrenheit(0)) # 32.0 print(celsius_to_fahrenheit(100)) # 212.0

</details> **Exercise 2: Multiple Return Values** Write a function `circle_stats(radius)` that returns the circumference and area of a circle as a tuple. Use `math.pi`. <details><summary>Sample Solution</summary> ```python import math def circle_stats(radius): circumference = 2 * math.pi * radius area = math.pi * radius ** 2 return circumference, area print(circle_stats(1)) # (6.283185307179586, 3.141592653589793)

Exercise 3: Boolean Return
Write a function has_letter(s, char) that returns True if s contains char, False otherwise, without using in. Use a loop.

Sample Solution ```python def has_letter(s, char): for c in s: if c == char: return True return False

print(has_letter("hello", 'e')) # True print(has_letter("hello", 'z')) # False

</details> **Exercise 4: Return with Early Exit** Write a function `safe_divide(a, b)` that returns `a / b` if `b` is not zero, otherwise returns `None`. <details><summary>Sample Solution</summary> ```python def safe_divide(a, b): if b == 0: return None return a / b print(safe_divide(10, 2)) # 5.0 print(safe_divide(10, 0)) # None

Exercise 5: Returning a Dictionary
Write a function student_info(name, age, subjects) that returns a dictionary with keys 'name', 'age', and 'subjects'.

Sample Solution ```python def student_info(name, age, subjects): return {"name": name, "age": age, "subjects": subjects}

info = student_info("Alice", 30, ["Math", "Science"]) print(info)

</details> --- ### 🏠 Homework – Deeper Thinking #### Short Answer Questions **1. Quadratic Equation Solver** Write a function `solve_quadratic(a, b, c)` that returns the roots of `ax² + bx + c = 0`. Return `(root1, root2)` for two real roots, `(root, None)` for one, and `None` for none. Handle `a=0`. <details><summary>Sample Answer</summary> ```python import math def solve_quadratic(a, b, c): if a == 0: if b == 0: return None return (-c / b, None) d = b**2 - 4*a*c if d < 0: return None if d == 0: return (-b / (2*a), None) sqrt_d = math.sqrt(d) return ((-b - sqrt_d)/(2*a), (-b + sqrt_d)/(2*a))

2. Data Processing Pipeline with Return
Write a function process_data(data) that removes None and negative numbers, computes average, and returns a dictionary with stats.

Sample Answer ```python def process_data(data): cleaned = [x for x in data if x is not None and x >= 0] if not cleaned: return {"original_count": len(data), "cleaned_count": 0, "average": None, "max": None, "min": None} return { "original_count": len(data), "cleaned_count": len(cleaned), "average": sum(cleaned) / len(cleaned), "max": max(cleaned), "min": min(cleaned) } ```

3. Password Generator (Returning String)
Write a function generate_password(length) that returns a random password containing uppercase, lowercase, and digits. Ensure at least one of each.

Sample Answer ```python import random, string def generate_password(length): if length < 3:raiseValueError("Lengthmustbeatleast3")chars = [random.choice(string.ascii_uppercase), random.choice(string.ascii_lowercase),random.choice(string.digits)]all_chars = string.ascii_letters +string.digitschars+= [random.choice(all_chars) for_inrange(length-3)]random.shuffle(chars)return''.join(chars)```

Essay Questions

4. Function Composition with Return Values
Write a function compose(f, g) that returns a new function h such that h(x) = f(g(x)). Use it to create double_then_square and square_then_double.

Sample Answer ```python def compose(f, g): return lambda x: f(g(x))

def double(x): return 2x def square(x): return xx

double_then_square = compose(square, double) # square(double(x)) square_then_double = compose(double, square) # double(square(x)) print(double_then_square(3)) # 36 print(square_then_double(3)) # 18

</details> **5. Return with Generator (Yield)** Write a generator function `fibonacci_sequence(n)` that yields the first `n` Fibonacci numbers. Explain the difference between `return` and `yield`. <details><summary>Sample Answer</summary> ```python def fibonacci_sequence(n): a, b = 0, 1 for _ in range(n): yield a a, b = b, a + b for num in fibonacci_sequence(10): print(num)

return ends the function and sends back a single value; yield produces a value and pauses the function, allowing it to resume later, generating a sequence lazily.

Homework Hints

Summary

In this tutorial, you have learned:

Mastering return is essential for writing modular, reusable, and testable code. With these skills, you can create functions that are true building blocks in your programs.

Next Steps: In Tutorial 4, we will cover Function Arguments – Positional, Keyword, and Default in more depth, including *args and **kwargs.

Happy returning!

Previous | Tutorial index | Next