This page is for anyone wiring Python functions that need to hand back more than one result. The usual pattern is comma-separated return values (a tuple), then unpacking at the call site. When the bundle grows or names help readability, reach for a dict, NamedTuple, or a dataclass.
def get_user():
name = "Alice"
age = 30
return name, age
name, age = get_user()
print(name)
print(age)That prints Alice on the first line and 30 on the second. Python packs those comma-separated values into a tuple; assignment unpacks that tuple into name and age. That pairing—tuple packing on return, sequence unpacking on assignment—is the default mental model for “multiple return values.” The assignment statement reference describes how unpacking binds targets; the return statement simply hands an expression back to the caller (here, the tuple expression formed by commas).
Tested on: Python 3.13.3; kernel 6.14.0-37-generic.
Can a Python function return multiple values?
Yes, in the sense that a single return can send back one object that carries several pieces of data. The idiomatic form is a tuple (often written without parentheses). Lists, dicts, NamedTuple, and dataclasses are containers for the same idea when you need mutability, keys, or clearer field names.
Return multiple values using commas
Separate values with commas after return. Python builds a tuple in source order:
def split_heading(text):
parts = text.split(None, 1)
if len(parts) == 2:
return parts[0], parts[1]
return parts[0], ""
label, body = split_heading("TODO buy milk")Running that snippet leaves label as TODO and body as buy milk. Writing return (a, b) is the same for readers and callers; the comma creates the tuple.
Unpack multiple return values into variables
Sequence unpacking assigns each returned item to a name on the left. In the common case, the number of variables must match the length of the returned sequence, or Python raises ValueError. Extended unpacking can capture “the rest” with *rest:
def report():
return "ok", 200, "a", "b", "c"
status, code, *payload, last = report()Here status is ok, code is 200, last is c, and payload is ['a', 'b'] because the starred name collects every middle item. The tutorial on tuples and sequences shows more unpacking patterns.
Return two values from a Python function
Two comma-separated values are a two-tuple. Order is part of the API: the first value must always mean the same thing (for example width then height), or callers will silently mis-bind.
def dimensions():
return 1920, 1080
width, height = dimensions()If only one side needs both together, assign to a single name: size = dimensions() and use size[0] / size[1], though named approaches below read better once the concept stops being “just a pair.”
Return multiple values as a tuple
This is the default for small, ordered bundles. Tuples are immutable, lightweight, and work well with type hints such as tuple[str, int]. Prefer tuples over lists when callers should treat the bundle as a fixed-shape record rather than a growable sequence. For background on the type itself, see Python tuple.
def stat_summary(values):
total = sum(values)
count = len(values)
return total, count, total / count
t, n, avg = stat_summary([2, 4, 6])Return multiple values as a list
Use a list when the result is naturally homogeneous and may need to change length or be mutated in place. Callers can still unpack if the length is fixed by contract. See Python list for general list behavior.
def top_n(scores, n):
return sorted(scores, reverse=True)[:n]
first, second, third = top_n([40, 10, 90, 55], 3)Remember that returning the same mutable list you keep inside a module can surprise callers; often you return a new list (as above) or a tuple of immutables.
Return multiple named values using a dictionary
Dicts document fields by key and tolerate optional keys. They shine when you do not want positional coupling or when different call sites care about different subsets. Python dictionary covers basics.
def fetch_config():
return {"host": "localhost", "port": 8080, "tls": True}
cfg = fetch_config()
print(cfg["host"], cfg["port"])Unpacking into names is possible with ** when matching a function’s parameters, but most code keeps the dict and uses key lookup or .get().
Return multiple named values using NamedTuple
collections.namedtuple adds attribute names to a tuple-like object: small, immutable, and readable. For larger APIs, consider typing’s NamedTuple subclass style in modern codebases; the idea is the same.
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
def origin_distance(vector):
x, y = vector
mag = (x * x + y * y) ** 0.5
return Point(x=x / mag, y=y / mag)
unit = origin_distance((3, 4))
print(unit.x, unit.y)After running, you should see 0.6 and 0.8. Official reference: collections.namedtuple.
Return multiple values using dataclass
Dataclasses add defaults, __repr__, and optional mutability while staying readable when you have several fields or expect the shape to evolve.
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
admin: bool = False
def load_user():
return User(name="Dev", age=31)
u = load_user()
print(u.name, u.admin)That prints Dev then False. Use frozen dataclasses when you want tuple-like immutability with named fields.
Ignore unwanted return values using underscore
Use _ (or multiple underscores) as a throwaway target when unpacking. Convention tells readers the value is intentionally unused.
def line_meta(s):
return s.strip(), len(s), s.upper()
_, length, _ = line_meta(" hi ")
print(length)Starred _ is not special; use *_ only in patterns where syntax allows. If you truly ignore all but one return, unpacking with _ keeps linters happier than bare tuple indexing when the tuple is small.
Common mistakes when returning multiple values
Mismatched unpacking is the most frequent error: a, b = func() when func returns three items raises ValueError: too many values to unpack. Fix by matching arity, collapsing to one variable, or using *rest.
Returning different container types on different branches (return 1, 2 vs return [1, 2]) forces every caller to branch; pick one representation.
Mutating a list that the function also stores as internal state leaks changes across calls—return a copy or an immutable tuple if callers should own the data.
For “half” of a pair, do not guess indexes long after the call; either unpack into named variables at the call site or return a dict / named object.
Python return multiple values quick reference table
| Approach | Typical return | Caller receives | Good when |
|---|---|---|---|
| Comma / tuple | return a, b |
a, b = f() |
Small fixed arity; fastest default |
| List | return [a, b, c] |
Sequence ops or unpack | Homogeneous, length may vary |
| Dict | return {"k": v} |
Key lookup | Many optional fields; avoid positional drift |
namedtuple |
return Row(...) |
Attributes or unpack | Immutable rows with names |
dataclass |
return Model(...) |
Attributes | Defaults, methods, clearer evolution |
Summary
Python’s simplest “multiple return” story is tuple packing and unpacking: return a, b and a, b = f(). That matches how the interpreter models assignment and keeps call sites short for pairs and triples. When order alone is not enough documentation, dicts, NamedTuple, and dataclasses give named fields without changing the fundamental rule—one object goes back across the return, and the caller unpacks or dereferences it deliberately. Stay consistent about types and arity, and use _ when a return slot is intentionally ignored.
References
- The
returnstatement - Assignment statements (unpacking)
- Tuples and sequences (tutorial)
collections.namedtuple- Data classes

