KTU S1

Functions with Multiple Return Values

By the end you should be able to: Write functions that return several values, explain that Python does this by returning a single tuple, and unpack the result correctly.

The syllabus names this separately because it surprises people coming from languages where a function returns exactly one thing.

def min_max(numbers):
    return min(numbers), max(numbers)


low, high = min_max([4, 9, 1, 7])
print(low, high)            # 1 9

What is actually happening

Python still returns one object — a tuple. The comma builds it:

def min_max(numbers):
    return min(numbers), max(numbers)

result = min_max([4, 9, 1, 7])
print(result)               # (1, 9)
print(type(result))         # <class 'tuple'>

low, high = result then unpacks that tuple, which is the same unpacking met in the tuples topic. So "multiple return values" is really "return a tuple, unpack it at the call" — and knowing that explains every behaviour below.

Unpacking must match

low, high = min_max(data)           # fine, 2 and 2
low, high, extra = min_max(data)    # ValueError: not enough values
low = min_max(data)                 # low is the whole tuple (1, 9)

Use _ for a value you do not need:

_, high = min_max(data)             # only the maximum wanted

Returning more than two

def stats(numbers):
    total = sum(numbers)
    return total, total / len(numbers), min(numbers), max(numbers)


total, avg, low, high = stats([10, 20, 30, 40])
# 100, 25.0, 10, 40

Past three or four values this becomes hard to read at the call site — nobody remembers which position is which. At that point return a dictionary instead:

def stats(numbers):
    return {
        "total":   sum(numbers),
        "average": sum(numbers) / len(numbers),
        "min":     min(numbers),
        "max":     max(numbers),
    }

s = stats([10, 20, 30, 40])
print(s["average"])         # 25.0 — self-describing

The tuple version is shorter; the dictionary version is readable six months later. For two or three values use a tuple, beyond that a dictionary.

Why this matters for decomposition

Multiple returns let a function answer a complete question in one call instead of being split artificially:

# Awkward: two functions, the list scanned twice
smallest = find_min(data)
largest  = find_max(data)

# Better: one pass, one call
smallest, largest = min_max(data)

That connects back to decomposition — a function should do one nameable job, and "find the smallest and largest" is one job even though it produces two answers.

Swapping, revisited

The swap from the tuples topic is this same mechanism:

a, b = b, a

The right-hand side builds the tuple (b, a) first, then unpacks it into a and b. Because the tuple captures both original values before either name is reassigned, no temporary variable is needed — the problem that took three lines in Module 2 pseudocode.