Multiple parameters and return values are where Python functions become truly powerful. You can accept any number of inputs (positional, keyword, variable) and return one value, several values (via tuple unpacking), or complex structures (dicts, objects). In 2026, good functions use type hints, clear docstrings, and thoughtful signatures to make code intuitive and safe.
Here’s a complete, practical guide to combining multiple parameters with flexible return patterns — with real-world examples and modern best practices.
1. Multiple Positional + Keyword Parameters
def calculate_total(
items: list[float], # positional required
tax_rate: float = 0.08, # keyword or positional
discount: float = 0.0 # keyword or positional
) -> float:
"""Calculate total after tax and discount."""
subtotal = sum(items)
subtotal *= (1 - discount)
return round(subtotal * (1 + tax_rate), 2)
# Positional call
print(calculate_total([100, 50])) # 162.0
# Mixed call
print(calculate_total([200], discount=0.1)) # 194.4
# Keyword call
print(calculate_total(items=[150], tax_rate=0.1)) # 165.0
2. Returning Multiple Values (Tuple Unpacking)
def divide_and_remainder(x: float, y: float) -> tuple[float, float]:
"""Return quotient and remainder."""
if y == 0:
raise ValueError("Division by zero")
quotient = x / y
remainder = x % y
return quotient, remainder
# Unpack directly
q, r = divide_and_remainder(10, 3)
print(f"Quotient: {q:.2f}, Remainder: {r}") # Quotient: 3.33, Remainder: 1.0
# Or receive as tuple
result = divide_and_remainder(10, 3)
print(result) # (3.333..., 1.0)
3. Variable Parameters (*args, **kwargs) with Multiple Returns
def stats_summary(*numbers: float, **options: bool) -> dict[str, float]:
"""
Compute stats on any number of values.
Args:
*numbers: Variable numbers to analyze
**options: show_median (bool), show_range (bool)
Returns:
Dictionary with computed statistics
"""
if not numbers:
return {"count": 0}
result = {
"count": len(numbers),
"mean": sum(numbers) / len(numbers),
"min": min(numbers),
"max": max(numbers)
}
if options.get("show_median", False):
sorted_nums = sorted(numbers)
mid = len(sorted_nums) // 2
result["median"] = sorted_nums[mid] if len(sorted_nums) % 2 else (sorted_nums[mid-1] + sorted_nums[mid]) / 2
if options.get("show_range", False):
result["range"] = result["max"] - result["min"]
return result
# Flexible call
print(stats_summary(1, 3, 5, 7, 9, show_median=True, show_range=True))
# {'count': 5, 'mean': 5.0, 'min': 1, 'max': 9, 'median': 5, 'range': 8}
4. Combining Everything (Real-World Example)
from typing import TypedDict, Literal
class OrderSummary(TypedDict):
subtotal: float
total: float
status: Literal["success", "empty", "error"]
def process_cart(
items: list[float], # required positional
customer_id: int, # required positional
/, # ?? end positional-only ??
discount: float = 0.0, # optional keyword/positional
*, # ?? start keyword-only ??
tax_rate: float = 0.08,
currency: str = "USD"
) -> OrderSummary:
"""Process shopping cart and return summary."""
if not items:
return {"subtotal": 0.0, "total": 0.0, "status": "empty"}
subtotal = sum(items)
discounted = subtotal * (1 - discount)
total = discounted * (1 + tax_rate)
return {
"subtotal": round(subtotal, 2),
"total": round(total, 2),
"status": "success"
}
# Valid calls
print(process_cart([100, 50], 12345)) # positional only
print(process_cart([200], 67890, discount=0.1)) # mix
print(process_cart(items=[150], customer_id=111, tax_rate=0.1)) # keyword-only
Best Practices & Common Patterns (2026 Edition)
- Type hints — always use them — makes code self-documenting and IDE-friendly
- Docstrings — document parameters, returns, and raises — use Google or NumPy style
- Order rule — positional ? positional-only (/) ? keyword/default ? keyword-only (*)
- Multiple returns — use tuples for 2–3 values; TypedDict/dataclasses for more or named results
- *args/**kwargs — use meaningfully (e.g.
*extra_fees,**config) — avoid overuse - Pitfall — mutable defaults — never do
def func(lst=[])— useNone+ check - Modern tip — use
typing.Selfin class methods,@overloadfor complex signatures
Conclusion
Multiple parameters and return values let you build flexible, expressive functions. In 2026, combine positional/keyword/default/variable args with type hints, clear docstrings, and structured returns (tuples, dicts, TypedDict). Thoughtful design makes functions intuitive to call, easy to understand, and safe to use — the foundation of clean, maintainable Python code.
Next time you write a function — plan its inputs and outputs first. A great signature feels natural and prevents bugs before they happen.