066. Return Values
Functions communicate results through return
066. Return Values
Aryan’s monitor is a pipeline: raw readings feed into classifiers, which feed into formatters, which feed into the display. Each function must return its result for the next function to consume:
def get_memory_pct():
mem = psutil.virtual_memory()
return mem.percent # return, not print
def classify(pct):
if pct >= 90: return "CRITICAL"
if pct >= 75: return "WARNING"
return "OK"
def format_status(pct, level):
bar = "#" * int(pct / 5)
return f"[{bar:<20}] {pct:.1f}% {level}"
# Pipeline: each function feeds the next
pct = get_memory_pct()
level = classify(pct)
status = format_status(pct, level)
print(status)If classify() used print() instead of return, format_status would receive None and crash. print() is for the end of the pipeline — the display layer. Everything before it must return.
Rule: if a function’s result will be used by another function, it must
return. Usingprint()instead ofreturnturns a reusable function into a dead end that can’t be tested or composed.
💡 Fun fact: In early BASIC, there was no return statement for values — subroutines communicated through shared global variables. The concept of a function returning a value to its caller, enabling pipelines like Aryan’s, was popularized by languages like Algol and later C in the 1970s.
⚠️ Watch out: The classic beginner mistake is calling print() inside a function thinking the caller will receive the printed value. print() always returns None — the value goes to the screen, not to the caller. This causes TypeError crashes that are confusing until you understand the distinction.
🤔 Think about it: If a function calls print() and also has a return statement, what does the caller receive? Can you think of a case where you’d intentionally want a function to both print and return a value?
Learning objectives
- Use return to send values back from functions
- Understand the difference between return and print
- Return multiple values as a tuple
Key concepts
- return
- return value
- print vs return
Try it
Concept detail
return exits the function and sends a value back to the caller. Without return, functions return None — a silent trap when the caller uses the result.
print vs return: print(x) — displays x to the console; function still returns None return x — sends x to the caller; execution ends here
A function that only prints is a dead end: result = my_func() # result is None if my_func only prints other_func(result) # crash: other_func gets None
Multiple return values (implicit tuple): def min_max(nums): return min(nums), max(nums) # returns a tuple
lo, hi = min_max([3, 1, 4]) # unpacked at call site
Early return: def find(items, target): for item in items: if item == target: return item # exits immediately return None # explicit fallback
A function that returns None by default should make that explicit: return None.
Solution
def mean(numbers):
total = sum(numbers)
avg = total / len(numbers)
return avg
def variance(numbers):
avg = mean(numbers)
squared_devs = [(x - avg) ** 2 for x in numbers]
result = sum(squared_devs) / len(numbers)
return result
def min_max(numbers):
return min(numbers), max(numbers)Tests
def test_mean():
assert mean([1, 2, 3, 4, 5]) == 3.0
def test_mean_not_none():
result = mean([1, 2, 3])
assert result is not None
def test_mean_single():
assert mean([42]) == 42.0
def test_variance():
# Classic dataset: [2,4,4,4,5,5,7,9], variance = 4.0
assert abs(variance([2, 4, 4, 4, 5, 5, 7, 9]) - 4.0) < 0.001
def test_variance_equal():
# All equal → variance is 0
assert variance([1, 1, 1]) == 0.0
def test_variance_not_none():
assert variance([1, 2, 3]) is not None
def test_min_max():
mn, mx = min_max([3, 1, 4, 1, 5, 9])
assert mn == 1
assert mx == 9