Return Multiple Values in Python Functions

Mateen Kiani

Mateen Kiani

Published on Sun Jul 27 2025·5 min read

mastering-multiple-return-values-in-python-functions

Ever found yourself needing to send back more than just one result from a function? In Python, returning multiple values is not only possible but also elegant. Yet many developers overlook the power of unpacking and structuring these returns for clearer, more maintainable code. Have you ever wondered how to choose between tuples, lists, dicts, or even more structured types when your function needs to give back a collection of results?

It all comes down to understanding each approach and its trade-offs. By learning how to pick the right return type—whether you want quick tuple unpacking, flexible lists, self-documenting namedtuples or dataclasses, or even streaming results via generators—you can write functions that communicate intent clearly, reduce bugs, and make downstream code easier to work with.

Basic Tuple Unpacking

The simplest way to return multiple values is with a tuple. Python packs comma-separated values into a tuple automatically. Unpacking makes using those values straight-forward:

def get_user_info(user_id):
# Simulated database lookup
name = "Alice"
age = 30
active = True
return name, age, active # returns a tuple
name, age, active = get_user_info(42)
print(name, age, active) # Alice 30 True

Why use tuples? They’re immutable, lightweight, and require no extra imports. Your caller can unpack in one line or assign the tuple to a single variable:

result = get_user_info(42)
print(result) # ('Alice', 30, True)

Tip: If you only care about some values, use _ as a placeholder when unpacking:

name, _, active = get_user_info(42)

This keeps your intent clear and your code tidy.

Lists and Dict Returns

Tuples work great for fixed sets, but sometimes you need flexibility or dynamic keys. Lists and dicts come into play when the number of return items can change or you want named access.

Using a list:

def filter_even(nums):
return [n for n in nums if n % 2 == 0]
evens = filter_even([1, 2, 3, 4, 5, 6])
print(evens) # [2, 4, 6]

If you end up with nested lists, you can flatten them using tools from recipes like the Python flatten list guide.

Using a dict:

def stats(nums):
return {
'min': min(nums),
'max': max(nums),
'count': len(nums)
}
data = stats([10, 5, 8, 3])
print(data['max']) # 10

Tip: A dict return is self-documenting. You don’t need to remember index positions, you just use keys.

You can iterate over or unpack a dict return easily:

for key, value in data.items():
print(key, value)

(See more on how to iterate dict returns.)

Namedtuple and Dataclass

When you want the brevity of tuples plus the readability of dicts, namedtuple and dataclass shine.

from collections import namedtuple
User = namedtuple('User', ['name', 'age', 'active'])
def get_user():
return User(name='Bob', age=25, active=False)
user = get_user()
print(user.name, user.age)

For Python 3.7+, dataclass adds type hints and default values:

from dataclasses import dataclass
@dataclass
class User:
name: str
age: int = 0
active: bool = True
def get_user():
return User('Eve', age=28)
user = get_user()
print(user) # User(name='Eve', age=28, active=True)

These structures give you attribute access, immutability control, and built-in methods like _asdict() for namedtuples or . __repr__() for dataclasses. They make your code more explicit and reduce errors when fields shift around.

Generator and Yield

What if you don’t want to collect everything at once? Generators let you yield values one at a time. This is useful for large data or streams:

def read_lines(filepath):
with open(filepath) as f:
for line in f:
yield line.strip(), len(line)
for content, length in read_lines('data.txt'):
print(f"{content[:10]}... ({length} chars)")

Here, the function returns a sequence of (content, length) pairs without loading the entire file into memory.

Tip: Use next() on a generator to fetch one result or wrap it in list() to materialize all pairs.

Generators give you lazy evaluation and can return an infinite sequence as well:

def counter():
i = 0
while True:
yield i
i += 1

Comparison Table

MethodSyntax EaseMutabilityNamed AccessWhen to Use
Tuplereturn a, bImmutableNoSimple fixed returns
Listreturn [a,b]MutableNoDynamic length
Dictreturn {}MutableYesSelf-documenting keyed results
namedtuplereturn X(...)ImmutableYesLightweight, tuple-like
dataclassreturn X(...)Mutable/ImmYesStructured, with type hints
Generator (yield)yield a, bn/aNoStreaming or large datasets

This table helps you pick the return style that fits your use case.

Best Practices

  1. Match Intent: If the number and order of values are fixed, use tuples or namedtuples.
  2. Clarity: Choose dicts or dataclasses when you want named access and self-documenting fields.
  3. Performance: For large or lazy sequences, prefer generators to avoid memory spikes.
  4. Documentation: Always mention what your function returns in the docstring:
def stats(nums):
"""
Returns a dict with keys 'min', 'max', 'count'.
"""
# ...
  1. Error Handling: Decide if your function should raise exceptions or return error flags as part of its multiple values (e.g., (result, error) style).
  2. Unpacking: When calling, unpack only what you need:
name, *_ = get_user_info(5)

Keep your callers in mind: clear returns lead to clearer usage.

Conclusion

Returning multiple values in Python functions is a simple pattern with big benefits. Tuples keep things quick and dirty, lists and dicts offer flexibility or clarity, namedtuple and dataclass bring structure, and generators can stream data efficiently. By choosing the right approach, you communicate intent to fellow developers, reduce bugs, and make your codebase easier to maintain. Next time you write a function that needs to hand back more than one thing, pause and pick the style that fits best. Your future self (and your team) will thank you.


Mateen Kiani
Mateen Kiani
kiani.mateen012@gmail.com
I am a passionate Full stack developer with around 4 years of experience in MERN stack development and 1 year experience in blockchain application development. I have completed several projects in MERN stack, Nextjs and blockchain, including some NFT marketplaces. I have vast experience in Node js, Express, React and Redux.