🔄 Returning Values

Return statements are how functions communicate results back to the code that calls them. Python functions can return single values, multiple values, or different values based on conditions, making them powerful tools for data processing and decision-making workflows.

# Different types of return values
def calculate_stats(numbers):
    """Return multiple statistics about a list of numbers"""
    if not numbers:
        return None, None, None  # Handle empty list
    
    total = sum(numbers)
    average = total / len(numbers)
    maximum = max(numbers)
    
    return total, average, maximum  # Return multiple values

# Use the returned values
scores = [85, 92, 78, 96, 88]
total, avg, max_score = calculate_stats(scores)

print(f"Total: {total}, Average: {avg:.1f}, Max: {max_score}")

🎯 Single Value Returns

Returning single values is the most common pattern, where functions perform calculations or operations and send back one result to the caller.

def calculate_discount(price, discount_percent):
    """Calculate discounted price"""
    discount_amount = price * (discount_percent / 100)
    return price - discount_amount

def validate_password(password):
    """Check if password meets requirements"""
    if len(password) < 8:
        return False
    if not any(char.isdigit() for char in password):
        return False
    return True

# Single value returns
discounted_price = calculate_discount(100, 15)
is_valid = validate_password("mypass123")

print(f"Discounted price: ${discounted_price}")
print(f"Password valid: {is_valid}")

⚡ Multiple Value Returns

Python functions can return multiple values simultaneously using tuple unpacking, enabling complex calculations that produce several related results in one operation.

def parse_name(full_name):
    """Split full name into first and last name"""
    parts = full_name.strip().split()
    if len(parts) >= 2:
        return parts[0], parts[-1]  # First and last
    return parts[0], ""  # Only first name provided

def get_file_info(filename):
    """Extract filename and extension"""
    if '.' in filename:
        name, extension = filename.rsplit('.', 1)
        return name, extension
    return filename, ""

# Unpack multiple return values
first, last = parse_name("Alice Johnson")
name, ext = get_file_info("document.pdf")

print(f"Name: {first} {last}")
print(f"File: {name}, Extension: {ext}")

🚀 Conditional Returns

Functions often need to return different values based on input conditions or calculation results, providing flexible responses to various scenarios.

def get_grade_info(score):
    """Return letter grade and pass/fail status"""
    if score >= 90:
        return "A", True, "Excellent"
    elif score >= 80:
        return "B", True, "Good"
    elif score >= 70:
        return "C", True, "Satisfactory"
    elif score >= 60:
        return "D", True, "Passing"
    else:
        return "F", False, "Needs Improvement"

def process_user_login(username, password):
    """Return login result with appropriate message"""
    if not username:
        return False, "Username required"
    if not password:
        return False, "Password required"
    if len(password) < 6:
        return False, "Password too short"
    return True, "Login successful"

# Handle different return scenarios
grade, passed, comment = get_grade_info(87)
success, message = process_user_login("alice", "secret123")

print(f"Grade: {grade}, Passed: {passed}, {comment}")
print(f"Login: {success}, {message}")

📊 Return Value Types Comparison

Return TypeSyntaxUse CaseExample
Single Valuereturn valueSimple calculationsreturn price * 1.08
Multiple Valuesreturn val1, val2Related calculationsreturn width, height
Conditionalif condition: return val1; else: return val2Different scenariosGrade calculation
Early Returnif error: return NoneError handlingInput validation
None (implicit)No return statementSide effects onlyPrint or file operations

🌟 Early Returns for Error Handling

Early returns improve code readability by handling error conditions first, allowing the main logic to proceed without nested if statements.

def calculate_bmi(weight, height):
    """Calculate BMI with input validation"""
    # Early returns for invalid input
    if weight <= 0:
        return None, "Weight must be positive"
    if height <= 0:
        return None, "Height must be positive"
    
    # Main calculation logic
    bmi = weight / (height ** 2)
    
    # Categorize BMI
    if bmi < 18.5:
        category = "Underweight"
    elif bmi < 25:
        category = "Normal"
    elif bmi < 30:
        category = "Overweight"
    else:
        category = "Obese"
    
    return bmi, category

# Test with different inputs
bmi1, result1 = calculate_bmi(70, 1.75)
bmi2, result2 = calculate_bmi(-5, 1.75)

print(f"BMI 1: {bmi1:.1f} ({result1})")
print(f"BMI 2: {bmi2} - {result2}")

💡 Returning Data Structures

Functions can return complex data structures like lists, dictionaries, or custom objects to organize related information effectively.

def create_user_summary(name, age, email):
    """Create a user summary dictionary"""
    return {
        'name': name,
        'age': age,
        'email': email,
        'id': name.lower().replace(' ', '_'),
        'active': True
    }

def get_even_odd_numbers(numbers):
    """Separate numbers into even and odd lists"""
    even = [n for n in numbers if n % 2 == 0]
    odd = [n for n in numbers if n % 2 == 1]
    return even, odd

def generate_report_data(sales_data):
    """Generate comprehensive sales report"""
    return {
        'total_sales': sum(sales_data),
        'average_sale': sum(sales_data) / len(sales_data),
        'best_day': max(sales_data),
        'total_days': len(sales_data),
        'sales_list': sales_data
    }

# Work with returned data structures
user = create_user_summary("Alice Johnson", 28, "alice@example.com")
even_nums, odd_nums = get_even_odd_numbers([1, 2, 3, 4, 5, 6])
report = generate_report_data([100, 150, 200, 175])

print(f"User ID: {user['id']}")
print(f"Even: {even_nums}, Odd: {odd_nums}")
print(f"Sales report: {report['total_sales']} total")

📚 Practical Applications

API Response Functions

Functions that return structured data work perfectly for API responses where different endpoints need to return consistent formats.

def api_success(data, message="Success"):
    """Return standardized API success response"""
    return {
        'success': True,
        'message': message,
        'data': data,
        'timestamp': '2024-01-15 10:30:00'
    }

def api_error(error_message, error_code=400):
    """Return standardized API error response"""
    return {
        'success': False,
        'error': error_message,
        'code': error_code,
        'timestamp': '2024-01-15 10:30:00'
    }

# Use standardized responses
user_data = {'name': 'Alice', 'id': 123}
success_response = api_success(user_data, "User retrieved successfully")
error_response = api_error("User not found", 404)

print("Success:", success_response)
print("Error:", error_response)

Data Validation Functions

Functions that return validation results help create robust applications with clear error handling.

def validate_form_data(form_data):
    """Validate form data and return results"""
    errors = []
    
    if not form_data.get('name'):
        errors.append("Name is required")
    if not form_data.get('email') or '@' not in form_data['email']:
        errors.append("Valid email is required")
    if form_data.get('age', 0) < 18:
        errors.append("Must be 18 or older")
    
    if errors:
        return False, errors
    return True, "Form data is valid"

# Test validation
valid_form = {'name': 'Alice', 'email': 'alice@example.com', 'age': 25}
invalid_form = {'name': '', 'email': 'invalid', 'age': 16}

is_valid1, result1 = validate_form_data(valid_form)
is_valid2, result2 = validate_form_data(invalid_form)

print(f"Valid form: {is_valid1} - {result1}")
print(f"Invalid form: {is_valid2} - {result2}")

Hands-on Exercise

Create a function that calculates both the area and perimeter of a rectangle. Return both values so they can be used separately.

python
def rectangle_calculations(length, width):
    # TODO: Calculate area (length * width)
    # TODO: Calculate perimeter (2 * (length + width))
    # TODO: Return both area and perimeter
    pass

# TODO: Test the function and unpack the results
area, perimeter = rectangle_calculations(5, 3)
print(f"Area: {area}")
print(f"Perimeter: {perimeter}")

Solution and Explanation 💡

Click to see the complete solution
def rectangle_calculations(length, width):
    # Calculate area (length * width)
    area = length * width
    # Calculate perimeter (2 * (length + width))
    perimeter = 2 * (length + width)
    # Return both area and perimeter
    return area, perimeter

# Test the function and unpack the results
area, perimeter = rectangle_calculations(5, 3)
print(f"Area: {area}")
print(f"Perimeter: {perimeter}")

Key Learning Points:

  • 📌 Multiple return values: Use commas to return multiple values return value1, value2
  • 📌 Tuple unpacking: Assign multiple return values to separate variables
  • 📌 Related calculations: Perfect for functions that compute related values
  • 📌 Function organization: One function can perform multiple related calculations

Learn more about variable scope to understand how variables behave inside and outside functions.

Test Your Knowledge

Test what you've learned about returning values:

What's Next?

Now that you understand how functions return data, you're ready to learn about variable scope. Understanding where variables can be accessed is crucial for writing functions that work correctly with data.

Ready to continue? Check out our lesson on Variable Scope.

Was this helpful?

😔Poor
🙁Fair
😊Good
😄Great
🤩Excellent