If you’ve been writing Python for a while, you’ve probably seen a function return two or three values at once and wondered, “wait, is that a tuple?” Yes, it is. And learning how to return a tuple from a function is one of those small things that make your Python code a lot cleaner.
In this guide, I’m going to walk you through every practical way to return a tuple in Python — from the simplest one-liner to named tuples that make your code self-documenting. I’ll also cover the most common mistakes I see developers make (even experienced ones), plus show you when returning a tuple is the right call vs. other data structures.
By the end, you’ll know exactly which method to reach for and why.
What Is a Tuple? (Quick Recap)
A tuple is an ordered, immutable collection of values. Immutable means once you create it, you can’t change the values inside it.
# This is a tuple
coordinates = (40.7128, -74.0060)
# This is also a tuple — parentheses are optional
coordinates = 40.7128, -74.0060
print(type(coordinates)) # <class 'tuple'>
Tuples are great for grouping related values that belong together, like a latitude and longitude, a first name and last name, or a price and discount rate. They’re faster than lists and signal to anyone reading your code: “these values go together and shouldn’t be changed.”
Check out: Reverse a Tuple in Python
Why Return a Tuple From a Function?
Python functions can technically only return a single value. But when you separate values with commas in a return statement, Python automatically packs them into a tuple. This lets you send back multiple related values in one shot.
Here’s a real-world way to think about it: imagine a function that looks up a customer in a database. You don’t just want the name; you want the name, email, and account status. Instead of writing three separate functions or passing in a dictionary, you just return a tuple.
Method 1: Return a Tuple Without Parentheses (The Pythonic Way)
This is the most common way you’ll see it in professional Python code. You just separate your return values with commas, no parentheses needed.
def get_customer_info():
name = "Sarah Johnson"
email = "sarah.johnson@email.com"
state = "California"
return name, email, state
result = get_customer_info()
print(result)
# Output: ('Sarah Johnson', 'sarah.johnson@email.com', 'California')
print(type(result))
# Output: <class 'tuple'>
I executed the example code and added the screenshot below.

The Python documentation itself points out: “It is actually the comma which makes a tuple, not the parentheses.” So when you write return name, email, state, Python is doing the packing for you behind the scenes.
I use this method for most day-to-day functions. It’s clean, readable, and very Pythonic.
Read: Iterate Through Tuples in Python
Method 2: Return a Tuple With Explicit Parentheses
You can also wrap your return values in parentheses. The result is the same; it’s a personal style preference.
def get_screen_resolution():
width = 1920
height = 1080
return (width, height)
resolution = get_screen_resolution()
print(resolution)
# Output: (1920, 1080)
I executed the example code and added the screenshot below.

I personally use parentheses when the return value has many items or when it makes the code visually cleaner. Pick one style and be consistent within your project.
One important gotcha here: If you’re returning a single-element tuple, you MUST add a trailing comma inside the parentheses. Without it, Python won’t treat it as a tuple — it’ll just treat it as the value itself wrapped in parentheses.
# ❌ This does NOT return a tuple — it returns a string
def get_city_wrong():
return ("Chicago")
print(type(get_city_wrong())) # <class 'str'>
# ✅ This DOES return a tuple — note the trailing comma
def get_city_correct():
return ("Chicago",)
print(type(get_city_correct())) # <class 'tuple'>
This is one of the most common bugs I see beginners run into. The trailing comma is the signal, not the parentheses.
Method 3: Unpack a Returned Tuple Into Variables
When a function returns a tuple, you don’t have to work with it as a tuple. You can unpack it directly into individual variables on the same line. This makes your code much more readable.
def get_order_summary():
order_id = "ORD-10482"
total = 149.99
status = "Shipped"
return order_id, total, status
# Unpack directly into variables
order_id, total, status = get_order_summary()
print(f"Order {order_id}: ${total} — {status}")
# Output: Order ORD-10482: $149.99 — Shipped
I executed the example code and added the screenshot below.

This is so much better than doing result[0], result[1], result[2] — which tells you absolutely nothing about what those values are.
Ignore values you don’t need with _
Sometimes you only care about certain values in the returned tuple. You can use the _ convention to skip the rest:
def get_employee_details():
name = "Marcus Thompson"
department = "Engineering"
salary = 95000
return name, department, salary
# I only need the name and salary, not the department
name, _, salary = get_employee_details()
print(f"{name} earns ${salary:,}/year")
# Output: Marcus Thompson earns $95,000/year
Catch extra values with *
If the tuple has more values than you want to unpack into individual variables, use * to catch the rest as a list:
def get_quiz_scores():
return 92, 88, 95, 78, 100
first, second, *rest = get_quiz_scores()
print(first) # 92
print(second) # 88
print(rest) # [95, 78, 100]
Method 4: Return a Named Tuple (The Production-Grade Way)
This is the method most beginner tutorials skip, but it’s the one I reach for on any real project or shared codebase.
Here’s the problem with regular tuple returns: result[0], result[1], result[2] tells future readers (or future you) absolutely nothing. What’s index 0? No idea without looking up the function.
A namedtuple solves this by letting you access values by name using dot notation, while still being a fully valid tuple.
from collections import namedtuple
# Define the structure once at the top of your module
SalesReport = namedtuple('SalesReport', ['total', 'average', 'highest'])
def analyze_monthly_sales(sales_data):
total = sum(sales_data)
average = round(total / len(sales_data), 2)
highest = max(sales_data)
return SalesReport(total=total, average=average, highest=highest)
# Sample sales data for a retail store in Texas
monthly_sales = [12000, 15500, 9800, 13200, 11600, 16400]
report = analyze_monthly_sales(monthly_sales)
# Access by name — clear, self-documenting
print(f"Total Sales: ${report.total:,}") # Total Sales: $78,500
print(f"Average: ${report.average:,}") # Average: $13,083.33
print(f"Best Month: ${report.highest:,}") # Best Month: $16,400
# It's still a tuple — you can unpack it too
total, average, highest = report
I executed the example code and added the screenshot below.

See the difference? report.total vs result[0], which one would you rather read at 6 PM on a Friday? Named tuples are readable, self-documenting, and still lightweight like a regular tuple.
When to use namedtuple:
- When you’re returning 3+ values from a function
- When the function is used in multiple places across a codebase
- When other developers (or a future version of you) will read this code
- When you want the clarity of a class without the overhead
Method 5: Build and Return a Tuple Dynamically
Sometimes you don’t know the values at write time — you’re building a tuple from a list, filtering data, or collecting results in a loop. In those cases, use tuple() to convert your result.
def get_top_scores(*scores, n=3):
sorted_scores = sorted(scores, reverse=True)
return tuple(sorted_scores[:n])
top_three = get_top_scores(88, 95, 72, 100, 65, 91, n=3)
print(top_three)
# Output: (100, 95, 91)
You can also return a tuple from a filtered or computed list:
def get_passing_students(grade_dict, passing_grade=70):
passing = [name for name, grade in grade_dict.items() if grade >= passing_grade]
return tuple(passing)
grades = {
"Alex": 82,
"Jordan": 65,
"Taylor": 91,
"Morgan": 55,
"Casey": 78
}
passed = get_passing_students(grades)
print(passed)
# Output: ('Alex', 'Taylor', 'Casey')
Practical Real-World Example
Let me put a few of these methods together in a realistic scenario. Say you’re building a function for an e-commerce app that processes a customer order:
pythonfrom collections import namedtuple
OrderResult = namedtuple('OrderResult', ['order_id', 'subtotal', 'tax', 'total', 'status'])
def process_order(items, customer_state="TX"):
tax_rates = {"TX": 0.0625, "CA": 0.0725, "NY": 0.08, "FL": 0.06}
subtotal = sum(item['price'] * item['qty'] for item in items)
tax_rate = tax_rates.get(customer_state, 0.05)
tax = round(subtotal * tax_rate, 2)
total = round(subtotal + tax, 2)
order_id = f"ORD-{abs(hash(str(items))) % 100000:05d}"
status = "Confirmed"
return OrderResult(
order_id=order_id,
subtotal=subtotal,
tax=tax,
total=total,
status=status
)
cart = [
{"item": "Wireless Headphones", "price": 79.99, "qty": 1},
{"item": "Phone Case", "price": 19.99, "qty": 2},
{"item": "USB-C Cable", "price": 12.99, "qty": 3},
]
order = process_order(cart, customer_state="TX")
print(f"Order ID : {order.order_id}")
print(f"Subtotal : ${order.subtotal:.2f}")
print(f"Tax : ${order.tax:.2f}")
print(f"Total : ${order.total:.2f}")
print(f"Status : {order.status}")
Output:
Order ID : ORD-XXXXX
Subtotal : $151.94
Tax : $9.50
Total : $161.44
Status : Confirmed
This is production-quality code. Named tuple, clear field names, easy to unpack or access by name, and a regular person can read it without needing documentation.
Common Mistakes to Avoid
These are the errors I see most often, even from developers who’ve been writing Python for years.
Mistake 1: Forget the Trailing Comma on Single-Element Tuples
# ❌ Wrong — this is NOT a tuple
def get_country():
return ("United States")
print(type(get_country())) # <class 'str'>
# ✅ Correct — the trailing comma makes it a tuple
def get_country():
return ("United States",)
print(type(get_country())) # <class 'tuple'>
Mistake 2: Unpack With the Wrong Number of Variables
def get_rgb():
return 255, 128, 0
# ❌ Wrong — too few variables
r, g = get_rgb() # ValueError: too many values to unpack
# ✅ Correct — match the number of values
r, g, b = get_rgb()
# ✅ Also fine — catch extras with *
r, *rest = get_rgb() # r = 255, rest = [128, 0]
Mistake 3: Try to Modify a Returned Tuple
def get_config():
return "localhost", 5432, "mydb"
config = get_config()
config[1] = 5433 # ❌ TypeError: 'tuple' object does not support item assignment
If you need to modify the returned values, either:
- Return a list instead of a tuple
- Convert the tuple to a list: config = list(get_config())
- Or rethink whether the data should be mutable in the first place
Mistake 4: Return Tuples With Inconsistent Lengths
# ❌ Bad — different return paths return different-length tuples
def find_user(user_id):
if user_id == 1:
return "Alice", "alice@email.com", "Admin" # 3 values
else:
return "Not found", None # 2 values — this will break unpacking
name, email, role = find_user(99) # ValueError — only 2 values came back
If your function has multiple return paths, make sure all of them return the same number of values. Use None as a placeholder when a value doesn’t exist:
# ✅ Better — consistent length across all paths
def find_user(user_id):
if user_id == 1:
return "Alice", "alice@email.com", "Admin"
else:
return None, None, None
When Should You Return a Tuple vs. a Dictionary vs. a Dataclass?
This is a question I get asked in almost every Python training session I run. Here’s my honest take:
| Situation | Use This |
|---|---|
| 2–3 simple related values | return x, y (implicit tuple) |
| 3+ values that need clear names | namedtuple |
| Values that might need to change after return | list or dict |
| Complex data with methods/logic | dataclass |
| Public API returning structured data | dataclass or TypedDict |
| Quick utility functions | Plain tuple |
A tuple says: “these values are fixed and belong together.” If that’s true for your use case, a tuple is the right call.
Return a Tuple of Tuples
You can also return a tuple that contains other tuples inside it. This comes up when you’re working with coordinate data, grid layouts, or any kind of 2D structure.
def get_us_city_coordinates():
new_york = (40.7128, -74.0060)
los_angeles = (34.0522, -118.2437)
chicago = (41.8781, -87.6298)
return new_york, los_angeles, chicago
cities = get_us_city_coordinates()
print(cities)
# Output: ((40.7128, -74.006), (34.0522, -118.2437), (41.8781, -87.6298))
# Loop through them
city_names = ["New York", "Los Angeles", "Chicago"]
for name, (lat, lon) in zip(city_names, cities):
print(f"{name}: lat={lat}, lon={lon}")
Quick Decision Guide
Not sure which method to use? Here’s the one-sentence version of each:
- Implicit return (return x, y) — use this 80% of the time for simple returns
- Explicit parentheses (return (x, y)) — same as above, just a style choice
- Tuple unpacking — use this when consuming the returned tuple in the calling code
- namedtuple — use this when 3+ values are returned and readability matters
- tuple() constructor — use this when building a tuple dynamically from a list
Frequently Asked Questions
Can a Python function return a tuple of tuples?
Yes, absolutely. Any value can be inside a tuple — including another tuple. This is common when returning grid data, coordinate pairs, or grouped records.
What’s the difference between returning a tuple and returning a list?
Tuples are immutable (can’t be changed), lighter in memory, and signal that the values are fixed. Lists are mutable and better when the caller might need to add, remove, or modify items.
Should I use namedtuple or a dataclass?
For simple read-only return values, namedtuple is great. If you need default values, methods, or mutable fields, go with dataclass (available in Python 3.7+). For most function return scenarios, namedtuple is the right weight.
Is returning a tuple slower than returning a list?
No — tuples are actually slightly faster than lists because of their immutability. Python can optimize tuple storage more efficiently.
Can I return an empty tuple?
Yes: return () returns an empty tuple. This is occasionally useful as a safe “no results” return value instead of None.
Wrapping Up
Returning a tuple in Python is easy once you understand the patterns. Start with the implicit return (return x, y) for simple cases. Upgrade to namedtuple as soon as you have 3+ return values or are writing shared code. And always watch out for the single-element tuple gotcha, that trailing comma matters more than it looks.
The patterns in this guide are what I use in real projects, and they’ll serve you well whether you’re building a small script or working on a larger codebase.
You may also like to read:
- Find the Length of a Tuple in Python
- Add Tuples to Lists in Python
- How to Fix TypeError: ’ tuple’ object is not callable in Python?
- Print a Tuple in Python

Bijay Kumar is an experienced Python and AI professional who enjoys helping developers learn modern technologies through practical tutorials and examples. His expertise includes Python development, Machine Learning, Artificial Intelligence, automation, and data analysis using libraries like Pandas, NumPy, TensorFlow, Matplotlib, SciPy, and Scikit-Learn. At PythonGuides.com, he shares in-depth guides designed for both beginners and experienced developers. More about us.