{ "cells": [ { "cell_type": "markdown", "id": "c5793bda", "metadata": {}, "source": [ "# Lesson 06 activity solution: Functions challenge\n", "\n", "In this activity, you'll solve problems that build on what you've learned about functions in Lesson 06. These problems will require you to **apply function concepts**, **work with different types of parameters**, and **understand variable scope**.\n", "\n", "## Instructions:\n", "- Each problem has a clear objective\n", "- You may need to research, experiment, or combine multiple concepts\n", "- Test your solutions in the code cells provided\n", "- There are multiple ways to solve each problem - be creative!" ] }, { "cell_type": "markdown", "id": "62d9f312", "metadata": {}, "source": [ "---\n", "## Problem 1: The temperature converter\n", "\n", "**Objective:** Create a versatile temperature conversion function with default parameters.\n", "\n", "**Your Task:**\n", "Write a function called `convert_temperature(value, from_unit='C', to_unit='F')` that:\n", "- Converts temperatures between Celsius (C) and Fahrenheit (F)\n", "- Uses default parameters for `from_unit` and `to_unit`\n", "- Returns the converted temperature rounded to 1 decimal place\n", "- Handles invalid unit inputs by returning an error message\n", "\n", "**Conversion formulas:**\n", "- Celsius to Fahrenheit: `(C × 9/5) + 32`\n", "- Fahrenheit to Celsius: `(F - 32) × 5/9`\n", "\n", "**Test cases:**\n", "- `convert_temperature(100)` → 212.0 (default C to F)\n", "- `convert_temperature(32, 'F', 'C')` → 0.0\n", "\n", "**Hints:**\n", "- Use if-elif statements to handle different conversion cases\n", "- Use the `round()` function for the return value" ] }, { "cell_type": "code", "execution_count": null, "id": "5a5ee3ca", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test 1: 212.0\n", "Test 2: 0.0\n" ] } ], "source": [ "# Problem 1: Your solution here\n", "\n", "def convert_temperature(value, from_unit='C', to_unit='F'):\n", " '''\n", " Converts temperature between Celsius and Fahrenheit.\n", "\n", " Args:\n", " value (float): The temperature value to convert\n", " from_unit (str): The unit to convert from ('C' or 'F')\n", " to_unit (str): The unit to convert to ('C' or 'F')\n", " \n", " Returns:\n", " float: The converted temperature rounded to 1 decimal places\n", " '''\n", " \n", " # If converting to the same unit, return the original value\n", " if from_unit == to_unit:\n", " return round(float(value), 1)\n", " \n", " # Convert from Celsius to Fahrenheit\n", " if from_unit == 'C' and to_unit == 'F':\n", "\n", " result = (value * 9/5) + 32\n", " return round(result, 1)\n", " \n", " # Convert from Fahrenheit to Celsius\n", " elif from_unit == 'F' and to_unit == 'C':\n", "\n", " result = (value - 32) * 5/9\n", " return round(result, 1)\n", " \n", " else:\n", " return \"Invalid unit. Use 'C' for Celsius or 'F' for Fahrenheit.\"\n", "\n", "# Test cases\n", "print('Test 1:', convert_temperature(100))\n", "print('Test 2:', convert_temperature(32, 'F', 'C'))\n" ] }, { "cell_type": "markdown", "id": "372ddd91", "metadata": {}, "source": [ "---\n", "## Problem 2: The flexible statistics calculator\n", "\n", "**Objective:** Create a function that uses *args to calculate statistics on any number of values.\n", "\n", "**Your Task:**\n", "Write a function called `calculate_stats(*numbers, operation='mean')` that:\n", "- Accepts any number of numeric arguments using `*numbers`\n", "- Has a keyword parameter `operation` with default value `'mean'`\n", "- Supports these operations:\n", " - `'mean'`: Calculate the average\n", " - `'range'`: Calculate max - min\n", " - `'sum'`: Calculate the total\n", "- Returns the calculated result\n", "- Handles edge cases (empty input, invalid operation)\n", "\n", "**Test cases:**\n", "- `calculate_stats(1, 2, 3, 4, 5)` → 3.0 (mean)\n", "- `calculate_stats(10, 20, 30, operation='range')` → 20\n", "- `calculate_stats(5, 10, 15, operation='sum')` → 30\n", "\n", "**Hints:**\n", "- Use `len(numbers)` to check if any numbers were provided\n", "- Python has built-in functions for mean, min, max and sum, you don't need to code the arithmetic yourself!" ] }, { "cell_type": "code", "execution_count": null, "id": "6a682da8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test 1 (mean): 3.0\n", "Test 2 (range): 20\n", "Test 3 (sum): 30\n" ] } ], "source": [ "# Problem 2: Your solution here\n", "\n", "def calculate_stats(*numbers, operation='mean'):\n", " '''\n", " Calculates various statistics on a variable number of values.\n", " \n", " Args:\n", " *numbers: Variable number of numeric values\n", " operation (str): The statistical operation to perform\n", " \n", " Returns:\n", " float/int: The calculated statistic\n", " '''\n", "\n", " # Handle empty input\n", " if len(numbers) == 0:\n", " return 'Error: No numbers provided'\n", " \n", " # Calculate based on the operation\n", " if operation == 'mean':\n", " return sum(numbers) / len(numbers)\n", " \n", " elif operation == 'range':\n", " return max(numbers) - min(numbers)\n", " \n", " elif operation == 'sum':\n", " return sum(numbers)\n", " \n", " else:\n", " return f\"Error: Invalid operation '{operation}'\"\n", "\n", "# Test cases\n", "print('Test 1 (mean):', calculate_stats(1, 2, 3, 4, 5))\n", "print('Test 2 (range):', calculate_stats(10, 20, 30, operation='range'))\n", "print('Test 3 (sum):', calculate_stats(5, 10, 15, operation='sum'))\n" ] }, { "cell_type": "markdown", "id": "38aa6de1", "metadata": {}, "source": [ "---\n", "## Problem 3: The text analyzer\n", "\n", "**Objective:** Create a text analysis tool using functions with multiple return values.\n", "\n", "**Your Task:**\n", "Write a function called `analyze_text(text, case_sensitive=False)` that:\n", "- Takes a text string and optional case_sensitive boolean\n", "- Returns a tuple containing:\n", " 1. Total number of words\n", " 2. Total number of characters (excluding spaces)\n", " 3. Number of unique words\n", "- If `case_sensitive=False`, converts text to lowercase for analysis\n", "- Removes punctuation before counting words\n", "\n", "**Expected output:**\n", "- Words: 9\n", "- Characters: 43\n", "- Unique words: 5\n", "\n", "**Hints:**\n", "- Use `.split()` to break text into words\n", "- Use `.replace()` or string methods to remove punctuation\n", "- Read about the `set` data type for finding the number of unique words" ] }, { "cell_type": "code", "execution_count": null, "id": "33b0ef24", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Analyzing text:\n", "Text: Python is great! Python is powerful. Python is versatile.\n", "\n", "Total words: 9\n", "Total characters (no spaces): 46\n", "Unique words: 5\n" ] } ], "source": [ "# Problem 3: Your solution here\n", "\n", "def analyze_text(text, case_sensitive=False):\n", " '''\n", " Analyzes text and returns various statistics.\n", " \n", " Args:\n", " text (str): The text to analyze\n", " case_sensitive (bool): Whether to treat uppercase and lowercase as different\n", " \n", " Returns:\n", " tuple: (word_count, char_count, unique_words)\n", " '''\n", "\n", " # Convert to lowercase if not case sensitive\n", " if not case_sensitive:\n", " text = text.lower()\n", " \n", " # Remove punctuation\n", " punctuation = '.,!?;:\\'\"'\n", "\n", " for char in punctuation:\n", " text = text.replace(char, '')\n", " \n", " # Split into words\n", " words = text.split()\n", " \n", " # Calculate word count\n", " word_count = len(words)\n", " \n", " # Calculate character count (excluding spaces)\n", " char_count = sum(len(word) for word in words)\n", " \n", " # Calculate unique words\n", " unique_words = len(set(words))\n", " \n", " return word_count, char_count, unique_words\n", "\n", "# Test case\n", "text = 'Python is great! Python is powerful. Python is versatile.'\n", "\n", "print('Analyzing text:')\n", "print(f'Text: {text}\\n')\n", "\n", "word_count, char_count, unique_words = analyze_text(text)\n", "\n", "print(f'Total words: {word_count}')\n", "print(f'Total characters (no spaces): {char_count}')\n", "print(f'Unique words: {unique_words}')\n" ] }, { "cell_type": "markdown", "id": "7f61f020", "metadata": {}, "source": [ "---\n", "## Problem 4: Fixing function bugs\n", "\n", "**Objective:** Debug and fix code snippets that contain common function-related errors.\n", "\n", "**Your Task:**\n", "Below are three code snippets that contain bugs. For each one:\n", "1. Identify the error\n", "2. Fix the code\n", "3. Test that it works correctly\n", "4. Add a comment explaining what was wrong\n", "\n", "Run each fixed snippet to verify it works!" ] }, { "cell_type": "markdown", "id": "e509c52e", "metadata": {}, "source": [ "### Bug 1\n", "\n", "**Expected output:** \n", "```\n", "1\n", "2\n", "3\n", "```\n", "**Current error:** UnboundLocalError" ] }, { "cell_type": "code", "execution_count": 4, "id": "4bc42d43", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "2\n", "3\n" ] } ], "source": [ "# Bug 1: Fix the code below\n", "# Error: UnboundLocalError - trying to modify global variable without 'global' keyword\n", "\n", "counter = 0\n", "\n", "def increment():\n", "\n", " global counter # Declare counter as global to modify it\n", " counter = counter + 1\n", "\n", " return counter\n", "\n", "print(increment())\n", "print(increment())\n", "print(increment())" ] }, { "cell_type": "markdown", "id": "060cac8a", "metadata": {}, "source": [ "### Bug 2\n", "\n", "**Expected output:**\n", "```\n", "List 1: ['apple']\n", "List 2: ['banana']\n", "List 3: ['cherry']\n", "```\n", "**Current (wrong) output:**\n", "```\n", "List 1: ['apple', 'banana', 'cherry']\n", "List 2: ['apple', 'banana', 'cherry']\n", "List 3: ['apple', 'banana', 'cherry']\n", "```" ] }, { "cell_type": "code", "execution_count": null, "id": "85500ff4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "List 1: ['apple']\n", "List 2: ['banana']\n", "List 3: ['cherry']\n" ] } ], "source": [ "# Bug 2: Fix the code below\n", "# Error: Mutable default argument - list is shared across all function calls\n", "# Fix: Use None as default and create a new list inside the function\n", "\n", "def add_to_list(item, my_list=None):\n", "\n", " if my_list is None:\n", " my_list = [] # Create a new list for each call\n", "\n", " my_list.append(item)\n", "\n", " return my_list\n", "\n", "list1 = add_to_list('apple')\n", "list2 = add_to_list('banana')\n", "list3 = add_to_list('cherry')\n", "\n", "print('List 1:', list1)\n", "print('List 2:', list2)\n", "print('List 3:', list3)\n" ] }, { "cell_type": "markdown", "id": "92697d30", "metadata": {}, "source": [ "### Bug 3\n", "\n", "**Expected behavior:** Should compare the final price and print appropriate message\n", "\n", "**Current error:** TypeError (comparing None with number)" ] }, { "cell_type": "code", "execution_count": null, "id": "333e1800", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Discount: $20.00\n", "Final price: $80.00\n", "Consider waiting for a better sale.\n" ] } ], "source": [ "# Bug 3: Fix the code below\n", "# Error: Function doesn't return a value, so result is None\n", "# Fix: Add a return statement to return the final_price\n", "\n", "def calculate_discount(price, discount_percent):\n", " discount_amount = price * (discount_percent / 100)\n", " final_price = price - discount_amount\n", " \n", " print(f'Discount: ${discount_amount:.2f}')\n", " print(f'Final price: ${final_price:.2f}')\n", " \n", " return final_price # Return the final price so it can be used by the caller\n", "\n", "result = calculate_discount(100, 20)\n", "\n", "if result < 50:\n", " print('Great deal!')\n", "\n", "else:\n", " print('Consider waiting for a better sale.')\n" ] }, { "cell_type": "markdown", "id": "5791b1a9", "metadata": {}, "source": [ "---\n", "## __Reflection questions__\n", "\n", "After completing the challenges, answer these questions:\n", "\n", "1. When would you use `*args` vs `**kwargs` in a function? Give an example scenario for each.\n", "2. What's the difference between a local and global variable? When should you use the `global` keyword?\n", "3. Why is it important for functions to return values instead of just printing them?\n", "4. What did you learn about default parameter values from the mutable default argument bug?\n", "5. How do you decide what a function should return: a single value, multiple values (tuple), or a data structure?" ] }, { "cell_type": "markdown", "id": "7df11dc9", "metadata": {}, "source": [ "1. **When to use *args vs **kwargs:** Use `*args` when you want to accept any number of positional arguments (e.g., a sum function that can add 2, 3, or 100 numbers). Use `**kwargs` when you want to accept any number of keyword arguments (e.g., a configuration function that accepts various named settings). Example: `calculate_stats(*numbers)` uses `*args`, while a function like `configure_settings(**options)` would use `**kwargs`.\n", "\n", "2. **Local vs global variables:** Local variables are defined inside a function and only accessible within that function. Global variables are defined outside functions and accessible throughout the program. Use the `global` keyword only when you need to modify a global variable from within a function. However, it's generally better to pass values as parameters and return results rather than modifying global variables.\n", "\n", "3. **Return values vs printing:** Functions that return values are reusable and composable: you can use their output as input to other functions, store results in variables, or use them in expressions. Functions that only print are limited to displaying information and can't be used in calculations or further processing. Return values make functions more flexible and testable.\n", "\n", "4. **Mutable default arguments:** Mutable default arguments (like lists or dictionaries) are created once when the function is defined, not each time it's called. This means all calls share the same mutable object, leading to unexpected behavior. The fix is to use `None` as the default and create a new mutable object inside the function if needed.\n", "\n", "5. **What to return:** Return a single value for simple operations (like calculating a sum). Return a tuple for multiple related values that naturally go together (like text analysis statistics). Return a data structure (list, dict) when you have a collection of values or when the amount of data varies. Consider what makes the function easiest to use for the caller." ] }, { "cell_type": "markdown", "id": "94f30647", "metadata": {}, "source": [ "---\n", "## Congratulations!\n", "\n", "You've completed the Lesson 06 Functions Challenge! You've practiced:\n", "- Writing functions with default parameters\n", "- Using *args and **kwargs for flexible function arguments\n", "- Understanding variable scope and the global keyword\n", "- Returning multiple values from functions\n", "- Debugging common function-related errors\n", "\n", "Functions are the building blocks of well-organized, reusable code. Mastering functions will make you a more effective programmer and help you write cleaner, more maintainable code. Keep practicing!" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.11" } }, "nbformat": 4, "nbformat_minor": 5 }