{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1fb294f4",
   "metadata": {},
   "source": [
    "# Functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "266589a7-5d90-4082-a8d9-b29670b913e4",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input",
     "thebe-init",
     "runnable"
    ]
   },
   "outputs": [],
   "source": [
    "import sys\n",
    "from pathlib import Path\n",
    "\n",
    "current = Path.cwd()\n",
    "for parent in [current, *current.parents]:\n",
    "    if (parent / '_config.yml').exists():\n",
    "        project_root = parent  # ← Add project root, not chapters\n",
    "        break\n",
    "else:\n",
    "    project_root = Path.cwd().parent.parent\n",
    "\n",
    "sys.path.insert(0, str(project_root));\n",
    "\n",
    "from shared import thinkpython, diagram, jupyturtle"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```{contents}\n",
    ":local:\n",
    ":depth: 2\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3341c96",
   "metadata": {},
   "source": [
    "**Built-in** vs **custom functions**: Python ships with functions like `print()` and `len()`, and you can also create your own custom functions."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83584650",
   "metadata": {},
   "source": [
    "## Built-in Functions\n",
    "\n",
    "In Python, built-in functions and built-in modules are both part of the standard tools the language gives you, but they serve different purposes. Built-in functions are ready to use without requiring any imports. They are automatically available in every Python program."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d447b0a5",
   "metadata": {},
   "source": [
    "Python built-in functions are tools for quick operations (such as length, conversion, and output). A few of them that you will use constantly:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a8398b7d",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello!\n",
      "3\n",
      "42\n",
      "6\n",
      "9\n"
     ]
    }
   ],
   "source": [
    "print(\"Hello!\")              # Output to screen\n",
    "\n",
    "len_num = len([1, 2, 3])     # 3: len() get the length of the argument\n",
    "num = int(\"42\")              # 42 (string → int); int() is a type constructor\n",
    "sum_num = sum([1, 2, 3])     # 6 (sum a list sequence)\n",
    "max_num = max(5, 2, 9)       # 9\n",
    "\n",
    "print(len_num)\n",
    "print(num)\n",
    "print(sum_num)\n",
    "print(max_num)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f9e757b",
   "metadata": {},
   "source": [
    "In the [Python Standard Library](https://docs.python.org/3/library/index.html), you can find all the Python built-in functions listed:\n",
    "\n",
    "```{figure} ../../figures/python-builtin-functions.png\n",
    "---\n",
    "width: 400px\n",
    "name: python-builtin-functions\n",
    "---\n",
    "[Python Built-In Functions](https://docs.python.org/3/library/functions.html#built-in-functions)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2853854e",
   "metadata": {},
   "source": [
    "Some built-in functions work together. For example:\n",
    "\n",
    "| Group                           | Functions                                                                                                                          | Notes                                                            |\n",
    "| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |\n",
    "| Numbers & math                  | `abs`, `divmod`, `max`, `min`, `pow`, `round`, `sum`                                                                               | `pow(a, b, mod=None)` supports modular exponentiation.           |\n",
    "| **Type construction** | **`bool`**, **`int`**, **`float`**,  **`str`**, **`list`**, **`tuple`**, `set`, **`dict`**, **`range`** | Convert or construct core types.                                 |\n",
    "| Object/attribute introspection  | **`type`**, **`id`**, `dir`, `ascii`                                                   | type() checks object types; id() shows object ID                     |\n",
    "| Iteration & functional tools    | `iter`, `next`, **`enumerate`**, `zip`, `map`, `filter`, `sorted`, `reversed`                                                          | Prefer comprehensions when clearer.                              |\n",
    "| Sequence/char helpers           | **`len`**, `ord`, `chr`, `slice`                                                                                                       | `len()` works on many containers.                                |\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-builtins-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Use Built-in Functions\n",
    "# Use built-in functions to summarize the ratings list.\n",
    "# Print exactly:\n",
    "# Count: 5\n",
    "# Best rating: 5\n",
    "# Average rating: 4.0\n",
    "ratings = [4, 5, 3, 4, 4]\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-builtins-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Count: 5\n",
      "Best rating: 5\n",
      "Average rating: 4.0\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "ratings = [4, 5, 3, 4, 4]\n",
    "\n",
    "count = len(ratings)\n",
    "best_rating = max(ratings)\n",
    "average_rating = sum(ratings) / count\n",
    "\n",
    "print(\"Count:\", count)\n",
    "print(\"Best rating:\", best_rating)\n",
    "print(\"Average rating:\", average_rating)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "ae253014-c393-4e4e-a20b-a2746146300f",
   "metadata": {},
   "source": [
    "## Functions (User-Defined)\n",
    "\n",
    "While Python's built-in functions are useful, the real power of programming comes from creating your own **functions**. \n",
    "\n",
    "A **function definition** specifies the name of a new function and the sequence of statements that run when the function is called.\n",
    "\n",
    "A function is a **reusable** block of code that performs a specific task. Functions help you organize code, avoid repetition, and make programs easier to understand and **maintain**.\n",
    "\n",
    "Use the `def` keyword to define a function. Key components of a function include:\n",
    "- **`def`**: Keyword that starts a function definition\n",
    "- **Function name**: Follows variable naming rules (snake_case)\n",
    "- **Parameters**: Input values (optional)\n",
    "- **Docstring**: Documentation string (recommended)\n",
    "- **Function body**: **Indented** (instead of `{}`) code that runs when the function is called"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cedb3eeb-0848-48dc-ab16-2e3c971a49ba",
   "metadata": {},
   "source": [
    "### Defining a Function\n",
    "\n",
    "Here's an example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "8fe4c780",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def print_lyrics():\n",
    "    print(\"I'm a lumberjack, and I'm okay.\")\n",
    "    print(\"I sleep all night and I work all day.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c412c935-4fb4-460f-8fd1-d33a4cca949b",
   "metadata": {},
   "source": [
    "The first line of the function definition is called the **header**, the rest is called the **body**.\n",
    "\n",
    "In the header we see three things:\n",
    "- `def` is a keyword that indicates that this is a function definition.\n",
    "- The `function name` of this function is `print_lyrics`. Anything that's a legal variable name is also a legal function name.\n",
    "- The empty `parentheses` after the name indicate that this function doesn't take any arguments.\n",
    "- The header has to end with a `colon`.\n",
    "\n",
    "In the body of this function we see that:\n",
    "- The body is `indented`. The Python Enhancement Proposal 8 ([PEP8](https://peps.python.org/pep-0008/#indentation)), the Python style guide, says \"Use `4 spaces` per indentation level\".\n",
    "- The body of a function can contain any number of statements of any kind.\n",
    "\n",
    "In this function, the body is two print statements.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e93a4caa-13b3-40e7-80f8-53c46f06ddfa",
   "metadata": {},
   "source": [
    "Defining a function creates a **function object**, which we can display like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "2b341929",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.print_lyrics()>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print_lyrics"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a70a546c-2dea-4426-9635-bb3fa49fcfe3",
   "metadata": {},
   "source": [
    "The output indicates that `print_lyrics` is a function that takes no arguments.\n",
    "`__main__` is the name of the module that contains `print_lyrics`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "7dcfdf27-824a-42ed-b625-d19db6f129b6",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Defining Function\n",
    "#1. Define a function named \"hello\", which prints \"hello, there\" when called\n",
    "#2. Showing the function object\n",
    "#3. Produce the same result as shown below.\n",
    "### Your code starts here\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6fd224b6-a7cd-469d-998f-3fdec8e2c287",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<function __main__.hello()>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### Solution\n",
    "def hello():\n",
    "    print(\"hello, there\")\n",
    "\n",
    "hello"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e624921d-3282-4ab8-b6c1-33a026d86837",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "### Calling a Function \n",
    "\n",
    "Now that we've defined a function, we can **call** it (make a **function call**) the same way we call built-in functions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "d2f8f9bc",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I'm a lumberjack, and I'm okay.\n",
      "I sleep all night and I work all day.\n"
     ]
    }
   ],
   "source": [
    "print_lyrics()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0b43d426-aded-4021-b77d-a70880c85e77",
   "metadata": {},
   "source": [
    "\n",
    "When the function runs, it executes the statements in the body, which display the first two lines of \"The Lumberjack Song\".\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ecae97d3-a218-4c36-b138-a84e2720d2d3",
   "metadata": {},
   "source": [
    "#### Parameters & Arguments\n",
    "\n",
    "Some of the Python built-in functions we have seen require **arguments**; for example, when you call `abs`, you pass a number as an **argument**. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3ad3281-e7e1-4d9b-9b5f-dd008d3ccbd1",
   "metadata": {},
   "source": [
    "The `print_lyrics()` does a simple `print` and is with **no parameters**. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6a40689-c753-424e-8cba-054208cb6de3",
   "metadata": {},
   "source": [
    "Functions can take one or more arguments; for example, `abs()` takes one, `math.pow` takes two: the base and the exponent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ab0891ea-4134-40db-9308-4c8e91a2ba18",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000\n",
      "8.0\n"
     ]
    }
   ],
   "source": [
    "import math\n",
    "\n",
    "print(abs(-1000))       ### 1 arg\n",
    "print(math.pow(2, 3))   ### 2 args"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "671790af-8652-4837-bca2-4cd0647529ca",
   "metadata": {},
   "source": [
    "#### With one parameter**\n",
    "\n",
    "Parameters allow functions to work with different inputs. Compare the `greet()` and `greet_personp()` functions, and you should see that parameters enhance the functionality of functions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "b2bd2ebd-97b7-4f07-bf83-1e9029023161",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Good morning!\n"
     ]
    }
   ],
   "source": [
    "def greet():\n",
    "    print(\"Good morning!\")\n",
    "\n",
    "greet()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "f037aa72-3d89-4b3a-8006-0deb9abd2a4b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, Alice!\n",
      "Hello, Bob!\n"
     ]
    }
   ],
   "source": [
    "def greet_person(name):\n",
    "    print(f\"Hello, {name}!\")\n",
    "\n",
    "greet_person(\"Alice\")  # Output: Hello, Alice!\n",
    "greet_person(\"Bob\")    # Output: Hello, Bob!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c1427fc1-4f03-481b-865c-e414d58173fb",
   "metadata": {},
   "source": [
    "Similarly, here is a definition for a function that takes an **argument**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "ed0942b7",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def print_twice(string):\n",
    "    print(string)\n",
    "    print(string)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18e6e4cd-1d4a-4625-ba97-1f4cafffe1f8",
   "metadata": {},
   "source": [
    "\n",
    "The variable name in parentheses is a **parameter**.\n",
    "When the function is called, the **argument**'s value is assigned to the parameter.\n",
    "For example, we can call `print_twice` like this.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "f4ede4ac",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam\n",
      "Spam\n"
     ]
    }
   ],
   "source": [
    "print_twice('Spam')"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "3182649f-f6a6-4a17-99b9-77795c4b4249",
   "metadata": {},
   "source": [
    "\n",
    "Running this function has the same effect as assigning the argument to the parameter and then executing the function's body. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "146a0494",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam\n",
      "Spam\n"
     ]
    }
   ],
   "source": [
    "string = 'Spam'\n",
    "print(string)\n",
    "print(string)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e65cd07b-88da-467e-896c-362d1f146482",
   "metadata": {},
   "source": [
    "You can also use a *variable as an argument*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "c1aaec89",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam, Spam, Spam, Spam\n",
      "Spam, Spam, Spam, Spam\n"
     ]
    }
   ],
   "source": [
    "line = 'Spam, Spam, Spam, Spam'\n",
    "print_twice(line)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "937dbece-125f-4bee-9441-1254eeddf3bf",
   "metadata": {},
   "source": [
    "\n",
    "In this example, the value of `line` gets assigned to the parameter `string`.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c946c55f-9674-4a4e-a9bd-c4fd3141840e",
   "metadata": {},
   "source": [
    "#### Multiple Parameters\n",
    "\n",
    "Once you have defined a function, you can use it inside another function.\n",
    "To demonstrate, we'll write functions that print the lyrics of \"The Spam Song\" (<https://www.songfacts.com/lyrics/monty-python/the-spam-song>).\n",
    "\n",
    "> Spam, Spam, Spam, Spam,  \n",
    "> Spam, Spam, Spam, Spam,  \n",
    "> Spam, Spam,  \n",
    "> (Lovely Spam, Wonderful Spam!)  \n",
    "> Spam, Spam,\n",
    "\n",
    "We'll start with the following function, which takes two parameters.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4bc9f2b3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def repeat(word, n):\n",
    "    print(word * n)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35362696-82fd-46c8-b6a9-4227008ddb55",
   "metadata": {},
   "source": [
    "We can use this function to print the first line of the song, like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "164089fd",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam, Spam, Spam, Spam, \n"
     ]
    }
   ],
   "source": [
    "repeat('Spam, ', 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af28f592-43ef-4322-aab1-9dba5e26c1f5",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "To display the first two lines, we can define a new function that uses `repeat`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "98ccaaec-4dc7-4225-b3d1-ca5cfcd27bfd",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Defining & Calling a Function\n",
    "#1. Define a function named \"add_two\" with two parameters\n",
    "#2. When called, the function prints the sum of the two number args\n",
    "### Your code starts here\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "7839870b-55b2-4bfc-899b-fde8b16bb6da",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The total is 5.\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "def add_two(num1, num2):\n",
    "    print(f\"The total is { num1 + num2 }.\")\n",
    "\n",
    "add_two(2, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8e939be-e6f2-4034-9a2f-8b35b2503e37",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "### Function Composition"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "5926003d",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def first_two_lines():\n",
    "    repeat('Spam, ', 4)\n",
    "    repeat('Spam, ', 4)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2bead628-da6c-43b3-b99f-6b3832bee1cb",
   "metadata": {},
   "source": [
    "And then call it like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "287f3dd8",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, Spam, Spam, \n"
     ]
    }
   ],
   "source": [
    "first_two_lines()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2095de7c-ce96-4b5f-bb1d-2b97c835a680",
   "metadata": {},
   "source": [
    "To display the last three lines, we can define another function, which also uses `repeat`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "b0d213e4",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def last_three_lines():\n",
    "    repeat('Spam, ', 2)\n",
    "    print('(Lovely Spam, Wonderful Spam!)')\n",
    "    repeat('Spam, ', 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "a0131d93",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam, Spam, \n",
      "(Lovely Spam, Wonderful Spam!)\n",
      "Spam, Spam, \n"
     ]
    }
   ],
   "source": [
    "last_three_lines()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15e8e11d-4795-45f2-a206-1b38fb8196b5",
   "metadata": {},
   "source": [
    "\n",
    "Finally, we can bring it all together with one function that prints the whole verse.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "bac1e85a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def print_verse():\n",
    "    first_two_lines()\n",
    "    last_three_lines()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "2d92ff2f",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, Spam, Spam, \n",
      "Spam, Spam, \n",
      "(Lovely Spam, Wonderful Spam!)\n",
      "Spam, Spam, \n"
     ]
    }
   ],
   "source": [
    "print_verse()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1527ef39-32c3-4a38-9113-bc020733c441",
   "metadata": {},
   "source": [
    "When we run `print_verse`, it calls `first_two_lines`, which calls `repeat`, which calls the built-in `print` function.\n",
    "That's a lot of functions.\n",
    "\n",
    "Of course, we could have done the same thing with fewer functions, but the point of this example is to show how functions can work together."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "185160a1",
   "metadata": {},
   "source": [
    "#### Nested Function Calls\n",
    "\n",
    "Nesting function calls refers to directly calling one function inside another's parentheses, creating a deep expression. It's a common syntax for passing a value to a series of operations in a single line. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "0fd070ff",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def add_one(x):\n",
    "    return x + 1\n",
    "\n",
    "def square(x):\n",
    "    return x * x\n",
    "\n",
    "### Nested function calls\n",
    "result = square(add_one(5)) # (5 + 1) ^ 2 = 36\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "079b24ba-c885-43e0-ad83-e9bb7cd5901f",
   "metadata": {},
   "source": [
    "#### Returning Value\n",
    "\n",
    "Most functions send a value back to the caller.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "8bfcd66c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def function_name(PARAMS):\n",
    "    \"\"\"\n",
    "    Docstring describing what the function does.\n",
    "    \"\"\"\n",
    "    # Function body\n",
    "    return value"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09ac91d6-10dd-4cda-9c6e-529f6a079b81",
   "metadata": {},
   "source": [
    "**Function with parameters and Return** "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "8486bb79-32eb-41c2-b3fd-c3d898a4918d",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def add_numbers(a, b):\n",
    "    \"\"\"Add two numbers and return the result.\"\"\"\n",
    "    result = a + b\n",
    "    return result               ### RETURN!!! ###\n",
    "\n",
    "add_numbers(5, 3)               # Returns 8\n",
    "sum2 = add_numbers(10, 20)      # Returns 30 and SAVED to sum2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "d85d6d12-1acd-4ae5-b6dc-6e22a32201c1",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Function in Function\n",
    "#1. Define a function named \"hellos\" that takes 1 parameter:  an integer\n",
    "#2. When called, hellos calls the \"hello\" function earlier n (the number of the integer) times\n",
    "#3. Try to produce the same result shown below.\n",
    "### Your code starts here\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "49d67982-472b-4ec6-97ae-09d4ddb94665",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello, there\n",
      "hello, there\n",
      "hello, there\n",
      "hello, there\n",
      "hello, there\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "def hello():\n",
    "    print(\"hello, there\")\n",
    "\n",
    "def hellos(n):\n",
    "    for i in range(n):\n",
    "        hello()\n",
    "\n",
    "hellos(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68e10da7-0ca6-4c01-b20e-6b13f80c86b3",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "### Docstrings\n",
    "**Docstrings** (documentation strings) are used to document **functions**/methods, _classes_, and _modules_. They use _triple quotes_ and should be the first statement after defining a function or class. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "10e12063",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, Homer!\n"
     ]
    }
   ],
   "source": [
    "### Function with docstring\n",
    "def greet(name):\n",
    "    \"\"\"\n",
    "    This function does xxx and yyy.         ### 1. what this function is about\n",
    "    \n",
    "    Args:                                   ### 2. input parameters\n",
    "        name: The person's name (string)    \n",
    "    \n",
    "    Returns:                                ### 3. what the function returns\n",
    "        A greeting message (string)\n",
    "    \"\"\"\n",
    "    return f\"Hello, {name}!\"\n",
    "\n",
    "message = greet(\"Homer\")       ### call the function\n",
    "print(message)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86be63e2",
   "metadata": {},
   "source": [
    "## Repetition\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a6013d6-76c8-40b1-9fbc-3e62f0775bdc",
   "metadata": {},
   "source": [
    "If we want to do something more than once, we can use a for statement. Here’s a simple example using `range()` to control the number of iterations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "05a756bb",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Twinkle, Twinkle, Little Star\n",
      "Twinkle, Twinkle, Little Star\n"
     ]
    }
   ],
   "source": [
    "lullabi = \"Twinkle, Twinkle, Little Star\" \n",
    "\n",
    "for i in range(2):\n",
    "    print(lullabi)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e079edc",
   "metadata": {},
   "source": [
    "You can put a `for` loop inside a **function**. For example, the function `print_lullaby (n)` takes a parameter named `n`, which has to be an integer, and displays the given number of verses."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "id": "173b74f5",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def print_lullaby(n):\n",
    "    for i in range(n):\n",
    "        print(lullabi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "bae57c49-0225-4d5d-8f9c-58bc81ead42b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Twinkle, Twinkle, Little Star\n",
      "Twinkle, Twinkle, Little Star\n",
      "Twinkle, Twinkle, Little Star\n",
      "Twinkle, Twinkle, Little Star\n",
      "Twinkle, Twinkle, Little Star\n"
     ]
    }
   ],
   "source": [
    "print_lullaby(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-repetition-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Repeat a Reminder\n",
    "# Define a function named repeat_reminder that prints a message n times.\n",
    "# Call it with \"Submit report\" and 3.\n",
    "# Print exactly:\n",
    "# Submit report\n",
    "# Submit report\n",
    "# Submit report\n",
    "\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-repetition-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Submit report\n",
      "Submit report\n",
      "Submit report\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "def repeat_reminder(message, n):\n",
    "    for _ in range(n):\n",
    "        print(message)\n",
    "\n",
    "repeat_reminder(\"Submit report\", 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ddbc2d6-b2c8-4633-8393-35bf96e53f4e",
   "metadata": {},
   "source": [
    "## List Arguments\n",
    "\n",
    "When you pass a list to a function, the function gets a reference to the\n",
    "list. If the function modifies the list, the caller sees the change. For\n",
    "example, `pop_first` uses the list method `pop` to remove the first element from a list.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "id": "22acd212",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def pop_first(lst):\n",
    "    return lst.pop(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba83ebdf-0840-4b1d-b096-9a64276f0c93",
   "metadata": {},
   "source": [
    "\n",
    "We can use it like this.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "id": "482244f1",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'apple'"
      ]
     },
     "execution_count": 105,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fruits = ['apple', 'banana', 'cherry']\n",
    "pop_first(fruits)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "240a866c-4ee0-4ad4-bec1-6d5e9190e783",
   "metadata": {},
   "source": [
    "The **return** value is the **first element**, which has been removed from the list -- as we can see by displaying the modified list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "id": "847b9a96",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['banana', 'cherry']"
      ]
     },
     "execution_count": 106,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fruits"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ccd87b7-1ecd-4855-8077-0d8e7aadeade",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "In this example, the **parameter** `lst` and the **argument** variable `fruits` are aliases for the same object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "3eaa11cd-d100-4fb2-a3ae-14e9ea9bd70d",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Function with Return\n",
    "#1. Define a function named \"num_list\" that takes one parameter: a list\n",
    "#2. When called, num_list returns the total of the number elements in the list\n",
    "#3. The argument needs to be a variable.\n",
    "#4. Use f-string to describe the output\n",
    "#5. Try to produce the same result shown below.\n",
    "### Your code starts here\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "67792974-e04f-4e03-a790-47ef9afa1d2d",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The total is 15.\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "def num_list(lst):\n",
    "    total = sum(lst)\n",
    "    return total\n",
    "\n",
    "lst = [ 1, 2, 3, 4, 5 ]\n",
    "total = num_list(lst)\n",
    "print(f\"The total is {total}.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "758072e1",
   "metadata": {},
   "source": [
    "## Loops and strings"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4be8047d",
   "metadata": {},
   "source": [
    "We know that a `for` loop using the `range` function can display a sequence of numbers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "id": "dd09b2ac",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "G a d s b y "
     ]
    }
   ],
   "source": [
    "for letter in 'Gadsby':\n",
    "    print(letter, end=' ')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e4355ca",
   "metadata": {},
   "source": [
    "Notice that I changed the name of the variable from `i` to `letter`, which provides more information about the value it refers to.\n",
    "The variable defined in a `for` loop is called the **loop variable**.\n",
    "\n",
    "Now that we can loop through the letters in a word, we can check whether it contains the letter \"e\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "f5bb0736",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "for letter in \"Gadsby\":\n",
    "    if letter == 'E' or letter == 'e':\n",
    "        print('This word has an \"e\"')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20386fc2",
   "metadata": {},
   "source": [
    "Before we go on, let's encapsulate that loop in a function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "cb177039",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def has_e():\n",
    "    for letter in \"Gadsby\":\n",
    "        if letter == 'E' or letter == 'e':\n",
    "            print('This word has an \"e\"')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "007e00e6",
   "metadata": {},
   "source": [
    "And let's make it a pure function that return `True` if the word contains an \"e\" and `False` otherwise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "44ace197",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def has_e():\n",
    "    for letter in \"Gadsby\":\n",
    "        if letter == 'E' or letter == 'e':\n",
    "            return True\n",
    "    return False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf6fd01d",
   "metadata": {},
   "source": [
    "We can generalize it to take the word as a parameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "7fa29a2e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def has_e(word):\n",
    "    for letter in word:\n",
    "        if letter == 'E' or letter == 'e':\n",
    "            return True\n",
    "    return False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8c9100f",
   "metadata": {},
   "source": [
    "Now we can test it like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "edf816ef",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "has_e('Gadsby')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "bf1885a7",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "has_e('Emma')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-string-loop-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Count a Character in Text\n",
    "# Define a function named count_letter that counts how many times target appears in text.\n",
    "# Use a loop, not the string count method.\n",
    "# Print exactly:\n",
    "# Count: 3\n",
    "text = \"banana\"\n",
    "target = \"a\"\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-string-loop-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Count: 3\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "def count_letter(text, target):\n",
    "    total = 0\n",
    "    for letter in text:\n",
    "        if letter == target:\n",
    "            total += 1\n",
    "    return total\n",
    "\n",
    "text = \"banana\"\n",
    "target = \"a\"\n",
    "\n",
    "print(\"Count:\", count_letter(text, target))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c224411c",
   "metadata": {},
   "source": [
    "## Scope\n",
    "\n",
    "When you create a variable inside a function, it is **local**, which\n",
    "means that it only exists inside the function.\n",
    "For example, the following function takes two arguments, concatenates them, and prints the result twice.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "id": "b19cf33e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def cat_twice(part1, part2):\n",
    "    cat = part1 + part2\n",
    "    print_twice(cat)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bbae91d2",
   "metadata": {},
   "source": [
    "\n",
    "Here's an example that uses it:\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "id": "b673e844",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'cat' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[113]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m      1\u001b[39m line1 = \u001b[33m'\u001b[39m\u001b[33mBing tiddle \u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m      2\u001b[39m line2 = \u001b[33m'\u001b[39m\u001b[33mtiddle bang.\u001b[39m\u001b[33m'\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[43mcat_twice\u001b[49m\u001b[43m(\u001b[49m\u001b[43mline1\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mline2\u001b[49m\u001b[43m)\u001b[49m\n        line1 \u001b[34m= \u001b[39m\u001b[34m'Bing tiddle '\u001b[39m\n        line2 \u001b[34m= \u001b[39m\u001b[34m'tiddle bang.'\u001b[39m",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[110]\u001b[39m\u001b[32m, line 3\u001b[39m, in \u001b[36mcat_twice\u001b[39m\u001b[34m(part1='Bing tiddle ', part2='tiddle bang.')\u001b[39m\n\u001b[32m      1\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mcat_twice\u001b[39m(part1, part2):\n\u001b[32m      2\u001b[39m     cat = part1 + part2\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m     \u001b[43mprint_twice\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcat\u001b[49m\u001b[43m)\u001b[49m\n        cat \u001b[34m= \u001b[39m\u001b[34m'Bing tiddle tiddle bang.'\u001b[39m",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[68]\u001b[39m\u001b[32m, line 2\u001b[39m, in \u001b[36mprint_twice\u001b[39m\u001b[34m(string='Bing tiddle tiddle bang.')\u001b[39m\n\u001b[32m      1\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mprint_twice\u001b[39m(string):\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m     \u001b[38;5;28mprint\u001b[39m(\u001b[43mcat\u001b[49m)\n\u001b[32m      3\u001b[39m     \u001b[38;5;28mprint\u001b[39m(cat)\n",
      "\u001b[31mNameError\u001b[39m: name 'cat' is not defined"
     ]
    }
   ],
   "source": [
    "%%expect NameError\n",
    "\n",
    "line1 = 'Bing tiddle '\n",
    "line2 = 'tiddle bang.'\n",
    "cat_twice(line1, line2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48efda48",
   "metadata": {},
   "source": [
    "\n",
    "When `cat_twice` runs, it creates a local variable named `cat`, which is destroyed when the function ends.\n",
    "If we try to display it, we get a `NameError`:\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79102273-96c0-4864-a6f7-7c12c11996d8",
   "metadata": {},
   "source": [
    "```python\n",
    "print(cat)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a757dc36",
   "metadata": {},
   "source": [
    "\n",
    "Outside of the function, `cat` is not defined. \n",
    "\n",
    "Parameters are also local.\n",
    "For example, outside `cat_twice`, there is no such thing as `part1` or `part2`.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "179c8b08",
   "metadata": {},
   "source": [
    "### The in operator\n",
    "\n",
    "The version of `has_e` we wrote in this chapter is more complicated than it needs to be.\n",
    "Python provides an operator, `in`,  that checks whether a character appears in a string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "0fa96ff0",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "word = 'Gadsby'\n",
    "'e' in word"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5de2cf4b",
   "metadata": {},
   "source": [
    "So we can rewrite `has_e` like this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "2d49ebc8",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def has_e(word):\n",
    "    if 'E' in word or 'e' in word:\n",
    "        return True\n",
    "    else:\n",
    "        return False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74555b33",
   "metadata": {},
   "source": [
    "And because the conditional of the `if` statement has a boolean value, we can eliminate the `if` statement and return the boolean directly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "228489f7",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def has_e(word):\n",
    "    return 'E' in word or 'e' in word"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "311bc7da",
   "metadata": {},
   "source": [
    "We can simplify this function even more using the method `lower`, which converts the letters in a string to lowercase.\n",
    "Here's an example."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "df3afb01",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'gadsby'"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "word.lower()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f197c30",
   "metadata": {},
   "source": [
    "`lower` makes a new string -- it does not modify the existing string -- so the value of `word` is unchanged."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "8c5d5fea",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Gadsby'"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "word"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "792533e6",
   "metadata": {},
   "source": [
    "Here's how we can use `lower` in `has_e`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "b30ff4ab",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def has_e(word):\n",
    "    return 'e' in word.lower()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "7d7c5ee5",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "has_e('Gadsby')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "6b70f6cc",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "has_e('Emma')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c56794e3",
   "metadata": {},
   "source": [
    "### Search\n",
    "\n",
    "Based on this simpler version of `has_e`, let's write a more general function called `uses_any` that takes a second parameter that is a string of letters.\n",
    "It returns `True` if the word uses any of the letters and `False` otherwise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "4076b285",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def uses_any(word, letters):\n",
    "    for letter in word.lower():\n",
    "        if letter in letters.lower():\n",
    "            return True\n",
    "    return False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8c82c253",
   "metadata": {},
   "source": [
    "Here's an example where the result is `True`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b2881ec9",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "uses_any('banana', 'aeiou')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf4c6463",
   "metadata": {},
   "source": [
    "And another where it is `False`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "26b48fed",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "uses_any('apple', 'xyz')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "11732649",
   "metadata": {},
   "source": [
    "`uses_any` converts `word` and `letters` to lowercase, so it works with any combination of cases."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "d423c614",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "uses_any('Banana', 'AEIOU')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8f2dfdd",
   "metadata": {},
   "source": [
    "The structure of `uses_any` is similar to `has_e`.\n",
    "It loops through the letters in `word` and checks them one at a time.\n",
    "If it finds one that appears in `letters`, it returns `True` immediately.\n",
    "If it gets all the way through the loop without finding any, it returns `False`.\n",
    "\n",
    "This pattern is called a **linear search**.\n",
    "In the exercises at the end of this chapter, you'll write more functions that use this pattern."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "178a1b09",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def uses_any(word, letters):\n",
    "    \"\"\"Checks if a word uses any of a list of letters.\n",
    "    \n",
    "    >>> uses_any('banana', 'aeiou')\n",
    "    True\n",
    "    >>> uses_any('apple', 'xyz')\n",
    "    False\n",
    "    \"\"\"\n",
    "    for letter in word.lower():\n",
    "        if letter in letters.lower():\n",
    "            return True\n",
    "    return False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac88033a",
   "metadata": {},
   "source": [
    "Each test begins with `>>>`, which is used as a prompt in some Python environments to indicate where the user can type code.\n",
    "In a doctest, the prompt is followed by an expression, usually a function call.\n",
    "The following line indicates the value the expression should have if the function works correctly.\n",
    "\n",
    "In the first example, `'banana'` uses `'a'`, so the result should be `True`.\n",
    "In the second example, `'apple'` does not use any of `'xyz'`, so the result should be `False`.\n",
    "\n",
    "To run these tests, we have to import the `doctest` module and run a function called `run_docstring_examples`.\n",
    "To make this function easier to use, I wrote the following function, which takes a function object as an argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "30af345f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from doctest import run_docstring_examples\n",
    "\n",
    "def run_doctests(func):\n",
    "    run_docstring_examples(func, globals(), name=func.__name__)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0cd1d78c",
   "metadata": {},
   "source": [
    "We haven't learned about `globals` and `__name__` yet -- you can ignore them.\n",
    "Now we can test `uses_any` like this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "20fdaf3f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "run_doctests(uses_any)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a03569e",
   "metadata": {},
   "source": [
    "`run_doctests` finds the expressions in the docstring and evaluates them.\n",
    "If the result is the expected value, the test **passes**.\n",
    "Otherwise it **fails**.\n",
    "\n",
    "If all tests pass, `run_doctests` displays no output -- in that case, no news is good news.\n",
    "To see what happens when a test fails, here's an incorrect version of `uses_any`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "020adbc5",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def uses_any_incorrect(word, letters):\n",
    "    \"\"\"Checks if a word uses any of a list of letters.\n",
    "    \n",
    "    >>> uses_any_incorrect('banana', 'aeiou')\n",
    "    True\n",
    "    >>> uses_any_incorrect('apple', 'xyz')\n",
    "    False\n",
    "    \"\"\"\n",
    "    for letter in word.lower():\n",
    "        if letter in letters.lower():\n",
    "            return True\n",
    "        else:\n",
    "            return False     # INCORRECT!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d24cc14",
   "metadata": {},
   "source": [
    "And here's what happens when we test it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "578f9163",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "**********************************************************************\n",
      "File \"__main__\", line 4, in uses_any_incorrect\n",
      "Failed example:\n",
      "    uses_any_incorrect('banana', 'aeiou')\n",
      "Expected:\n",
      "    True\n",
      "Got:\n",
      "    False\n"
     ]
    }
   ],
   "source": [
    "run_doctests(uses_any_incorrect)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91261e76",
   "metadata": {},
   "source": [
    "The output includes the example that failed, the value the function was expected to produce, and the value the function actually produced.\n",
    "\n",
    "If you are not sure why this test failed, you'll have a chance to debug it as an exercise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-scope-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Use Local Variables\n",
    "# Define a function that calculates a fee total without changing the original amount.\n",
    "# Print exactly:\n",
    "# Total with fee: 105\n",
    "# Original amount: 100\n",
    "amount = 100\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-scope-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total with fee: 105\n",
      "Original amount: 100\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "amount = 100\n",
    "\n",
    "def add_fee(amount):\n",
    "    fee = 5\n",
    "    total = amount + fee\n",
    "    return total\n",
    "\n",
    "print(\"Total with fee:\", add_fee(amount))\n",
    "print(\"Original amount:\", amount)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6eb4fb78",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "## Stack diagrams\n",
    "\n",
    "To keep track of which variables can be used where, it is sometimes useful to draw a **stack diagram**. \n",
    "Like state diagrams, stack diagrams show the value of each variable, but they also show the function each variable belongs to.\n",
    "\n",
    "Each function is represented by a **frame**.\n",
    "A frame is a box with the name of a function on the outside and the parameters and local variables of the function on the inside.\n",
    "\n",
    "Here's the **stack diagram** for the previous example (you can ignore the code):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6beb3090",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [],
   "source": [
    "from shared.diagram import make_frame, Stack\n",
    "d1 = dict(line1=line1, line2=line2)\n",
    "frame1 = make_frame(d1, name='__main__', dy=-0.3, loc='left')\n",
    "d2 = dict(part1=line1, part2=line2, cat=line1+line2)\n",
    "frame2 = make_frame(d2, name='cat_twice', dy=-0.3, \n",
    "                    offsetx=0.03, loc='left')\n",
    "d3 = dict(string=line1+line2)\n",
    "frame3 = make_frame(d3, name='print_twice', \n",
    "                    offsetx=0.04, offsety=-0.3, loc='left')\n",
    "d4 = {\"?\": line1+line2}\n",
    "frame4 = make_frame(d4, name='print', \n",
    "                    offsetx=-0.22, offsety=0, loc='left')\n",
    "stack = Stack([frame1, frame2, frame3, frame4], dy=-0.8)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b0411ceb",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [],
   "source": [
    "from shared.diagram import diagram, adjust\n",
    "width, height, x, y = [3.77, 2.9, 1.1, 2.65]\n",
    "ax = diagram(width, height)\n",
    "bbox = stack.draw(ax, x, y)\n",
    "# adjust(x, y, bbox)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08b0bfe5",
   "metadata": {},
   "source": [
    "\n",
    "The frames are arranged in a stack that indicates which function called\n",
    "which, and so on. Reading from the bottom, `print` was called by `print_twice`, which was called by `cat_twice`, which was called by `__main__` -- which is a special name for the topmost frame.\n",
    "When you create a variable outside of any function, it belongs to `__main__`.\n",
    "\n",
    "In the `print` frame, the question mark indicates that we don't know the parameter's name."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-stack-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Trace Function Calls\n",
    "# Use function calls to build a simple call trace.\n",
    "# Print exactly:\n",
    "# start order\n",
    "# apply discount\n",
    "# finish order\n",
    "\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-stack-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "start order\n",
      "apply discount\n",
      "finish order\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "def apply_discount():\n",
    "    print(\"apply discount\")\n",
    "\n",
    "def process_order():\n",
    "    print(\"start order\")\n",
    "    apply_discount()\n",
    "    print(\"finish order\")\n",
    "\n",
    "process_order()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "acb82147",
   "metadata": {},
   "source": [
    "## Tracebacks\n",
    "\n",
    "When a runtime error occurs in a function, Python displays the name of the function that was running, the name of the function that called it, and so on, up the stack.\n",
    "To see an example, I'll define a version of `print_twice` that contains an error -- it tries to print `cat`, which is a local variable in another function.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24e241df-81e0-4f79-b435-5b67e2296f40",
   "metadata": {},
   "source": [
    "```python\n",
    "def print_twice(string):\n",
    "    print(cat)\n",
    "    print(cat)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e175e40",
   "metadata": {},
   "source": [
    "\n",
    "Now here's what happens when we run `cat_twice`.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "2e5b60cd",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Exception reporting mode: Verbose\n"
     ]
    }
   ],
   "source": [
    "# This cell tells Jupyter to provide detailed debugging information\n",
    "# when a runtime error occurs, including a traceback.\n",
    "%xmode Verbose\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9e830bc-5d9e-4079-85e6-7a1707907153",
   "metadata": {},
   "source": [
    "```python\n",
    "line1 = 'Bing tiddle '\n",
    "line2 = 'tiddle bang.'\n",
    "cat_twice(line1, line2)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d0a8d35",
   "metadata": {},
   "source": [
    "\n",
    "The error message includes a **traceback**, which shows the function that was running when the error occurred, the function that called it, and so on.\n",
    "In this example, it shows that `cat_twice` called `print_twice`, and the error occurred in a `print_twice`.\n",
    "\n",
    "The order of the functions in the traceback is the same as the order of the frames in the stack diagram.\n",
    "The function that was running is at the bottom.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8b5c9ffd-af34-4508-bd5c-f2d1370caa45",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-traceback-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Fix a Type Error\n",
    "# The original expression tried to add text and a number.\n",
    "# Convert the text to an integer before adding.\n",
    "# Print exactly:\n",
    "# Next count: 8\n",
    "current_count = \"7\"\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ch02-functions-traceback-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Next count: 8\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "current_count = \"7\"\n",
    "next_count = int(current_count) + 1\n",
    "\n",
    "print(\"Next count:\", next_count)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "functions-cheat-sheet",
   "metadata": {},
   "source": [
    "## Python Functions Cheat Sheet\n",
    "\n",
    "Use this sheet to review function definitions, calls, parameters, and return values. Variable-length arguments (`*args` and `**kwargs`), lambda expressions, recursion, and nested function definitions are optional extensions beyond this section's core material. A function can return a tuple containing several results; unpacking assigns those results to separate variables.\n",
    "\n",
    "```{figure} ../../figures/python_functions_cheat_sheet.svg\n",
    ":name: python-functions-cheat-sheet\n",
    ":width: 100%\n",
    ":alt: Twelve Python function patterns, with definitions, calls, and expected output; the same examples appear in the text reference below.\n",
    "\n",
    "Python functions quick reference. Redrawn with corrected examples from the supplied reference image.\n",
    "```\n",
    "\n",
    "<details>\n",
    "<summary>Text reference: all twelve examples</summary>\n",
    "\n",
    "**1. Basic function**\n",
    "\n",
    "Define a reusable task.\n",
    "\n",
    "```python\n",
    "def greet():\n",
    "    print(\"Hello, Python!\")\n",
    "\n",
    "greet()\n",
    "# Hello, Python!\n",
    "```\n",
    "\n",
    "**2. Parameters and arguments**\n",
    "\n",
    "Parameters receive argument values.\n",
    "\n",
    "```python\n",
    "def add(a, b):\n",
    "    return a + b\n",
    "\n",
    "print(add(5, 3))\n",
    "# 8\n",
    "```\n",
    "\n",
    "**3. Default parameters**\n",
    "\n",
    "Use a default when an argument is omitted.\n",
    "\n",
    "```python\n",
    "def greet(name=\"Guest\"):\n",
    "    print(f\"Hello, {name}!\")\n",
    "\n",
    "greet()       # Hello, Guest!\n",
    "greet(\"Alice\") # Hello, Alice!\n",
    "```\n",
    "\n",
    "**4. Variable arguments: *args**\n",
    "\n",
    "Extra positional arguments form a tuple.\n",
    "\n",
    "```python\n",
    "def total(*numbers):\n",
    "    return sum(numbers)\n",
    "\n",
    "print(total(1, 2, 3, 4))\n",
    "# 10\n",
    "```\n",
    "\n",
    "**5. Keyword arguments: **kwargs**\n",
    "\n",
    "Extra keyword arguments form a dictionary.\n",
    "\n",
    "```python\n",
    "def user_info(**kwargs):\n",
    "    for key, value in kwargs.items():\n",
    "        print(f\"{key}: {value}\")\n",
    "\n",
    "user_info(name=\"Alice\", age=25)\n",
    "# name: Alice\n",
    "# age: 25\n",
    "```\n",
    "\n",
    "**6. Return statement**\n",
    "\n",
    "Send a value back to the caller.\n",
    "\n",
    "```python\n",
    "def square(x):\n",
    "    return x * x\n",
    "\n",
    "print(square(4))\n",
    "# 16\n",
    "```\n",
    "\n",
    "**7. Multiple results**\n",
    "\n",
    "Return a tuple; unpack its values.\n",
    "\n",
    "```python\n",
    "def calc(a, b):\n",
    "    return a + b, a - b, a * b\n",
    "\n",
    "added, diff, product = calc(5, 3)\n",
    "print(added, diff, product)\n",
    "# 8 2 15\n",
    "```\n",
    "\n",
    "**8. Lambda expression**\n",
    "\n",
    "Create a small anonymous function.\n",
    "\n",
    "```python\n",
    "square = lambda x: x * x\n",
    "\n",
    "print(square(5))\n",
    "# 25\n",
    "```\n",
    "\n",
    "**9. Recursion**\n",
    "\n",
    "Call the same function with a smaller task.\n",
    "\n",
    "```python\n",
    "# n must be a nonnegative integer.\n",
    "def factorial(n):\n",
    "    if n == 0:\n",
    "        return 1\n",
    "    return n * factorial(n - 1)\n",
    "\n",
    "print(factorial(5))  # 120\n",
    "```\n",
    "\n",
    "**10. Nested function**\n",
    "\n",
    "Define and call a function inside another.\n",
    "\n",
    "```python\n",
    "def outer():\n",
    "    def inner():\n",
    "        print(\"Inside inner function\")\n",
    "    inner()\n",
    "\n",
    "outer()\n",
    "# Inside inner function\n",
    "```\n",
    "\n",
    "**11. Higher-order function**\n",
    "\n",
    "Accept a function or return a function.\n",
    "\n",
    "```python\n",
    "def apply_func(f, x):\n",
    "    return f(x)\n",
    "\n",
    "def cube(n):\n",
    "    return n * n * n\n",
    "\n",
    "print(apply_func(cube, 3))  # 27\n",
    "```\n",
    "\n",
    "**12. Built-in functions**\n",
    "\n",
    "Use Python's ready-made functions.\n",
    "\n",
    "```python\n",
    "print(len([2, 4, 6]))  # 3\n",
    "print(max([2, 4, 6]))  # 6\n",
    "print(min([2, 4, 6]))  # 2\n",
    "print(sum([2, 4, 6]))  # 12\n",
    "print(type(5))        # <class 'int'>\n",
    "print(abs(-5))        # 5\n",
    "```\n",
    "\n",
    "</details>\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv (3.13.13)",
   "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.13.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
