This rule raises an issue when a function returns tuples of different lengths in different code paths.
When a function returns tuples of varying lengths, it creates an inconsistent API that is difficult to use correctly. Callers cannot reliably unpack the return value without checking its length first, which leads to fragile code.
Consider this example:
def process_data(value):
if value > 0:
return (value,) # Returns a 1-tuple
else:
return (value, value * 2) # Returns a 2-tuple
# Caller has no reliable way to unpack this
result = process_data(10)
x, y = result # ValueError if value > 0!
This forces callers to add defensive length-checks before unpacking, making the code fragile and harder to maintain. The function signature provides no indication that the return type varies, so developers must read the implementation or discover the behavior through runtime errors.
Consistent return types make code more predictable, easier to test, and less likely to cause unexpected failures in production.
Runtime errors from tuple unpacking may not surface during initial testing if certain code paths are not fully exercised, leading to production failures. The need for defensive length-checking also increases the maintenance burden and makes the API harder to document for new team members.
Make all return statements return tuples of the same length. Add placeholder values (like None or 0) to shorter tuples to
maintain consistency.
def calculate_stats(numbers):
if not numbers:
return (0,) # Noncompliant
total = sum(numbers)
average = total / len(numbers)
return (total, average)
def calculate_stats(numbers):
if not numbers:
return (0, 0) # Consistent 2-tuple
total = sum(numbers)
average = total / len(numbers)
return (total, average)
For complex return types, consider using typing.NamedTuple to make the return value self-documenting. Named tuples provide clear field
names and enforce a consistent structure, making the API easier to use and understand.
from typing import NamedTuple
class Stats(NamedTuple):
total: float
average: float
def calculate_stats(numbers) -> Stats:
if not numbers:
return Stats(total=0, average=0)
total = sum(numbers)
average = total / len(numbers)
return Stats(total=total, average=average)