{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f08005bf-16aa-4a52-b369-11d11da3aa6d",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "# Python Syntax"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cbefe58a-9ea2-44f3-8987-5d095422f9a0",
   "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",
   "id": "ch02-syntax-local-contents",
   "metadata": {},
   "source": [
    "```{contents}\n",
    ":local:\n",
    ":depth: 2\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62c9b998",
   "metadata": {},
   "source": [
    "<h2>Overview</h2>\n",
    "\n",
    "Python fundamentals set the stage for everything that follows in this book. In this chapter, you will learn how to write simple Python statements, store values in variables, make decisions with conditional logic, repeat work with loops, organize values in lists and dictionaries, and define reusable functions.\n",
    "\n",
    "The emphasis is practical fluency for data science and management work. You will use Python as a tool for representing business information, applying decision rules, summarizing repeated values, and preparing for NumPy and pandas in later chapters.\n",
    "\n",
    "```{figure} ../../figures/python-cheat-sheet-365.jpg\n",
    "---\n",
    "width: 100%\n",
    "name: python-cheat-sheet-365\n",
    "align: left\n",
    "---\n",
    "Python cheat sheet (365 Data Science).\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "143a1c10",
   "metadata": {},
   "source": [
    "## Input and Output"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a427552a",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [],
    "vscode": {
     "languageId": "markdown"
    }
   },
   "source": [
    "### `print()` and F-Strings\n",
    "\n",
    "In Python, the **`print()`** function is used to display output to the screen. It's one of the most commonly used functions for debugging, showing results, and interacting with users. When printing multiple values, a `,` can be used; or you may choose to concatenate the strings using the `+` operator. \n",
    "\n",
    "The `print()` function displays values to the console/command line:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "0944cf1c",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello, world!\n"
     ]
    }
   ],
   "source": [
    "print(\"hello, world!\")           ### print a string"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8568bcc",
   "metadata": {},
   "source": [
    "To print multiple values in one statement, you either **comma-separate** your values or **concatenate** the strings. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "d1aee52c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: Alice Age: 25\n",
      "Name: Alice Age: 25\n"
     ]
    }
   ],
   "source": [
    "print(\"Name:\", \"Alice\", \"Age:\", 25)       ### comma-separated\n",
    "print(\"Name:\" + \" Alice\" + \" Age:\", 25)   ### + concatenated"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "0848ef2c-d3a6-4a44-8de4-ec1bb339499d",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "can only concatenate str (not \"int\") to str",
     "output_type": "error",
     "traceback": [
      "\u001b[31mTypeError\u001b[39m\u001b[31m:\u001b[39m can only concatenate str (not \"int\") to str\n"
     ]
    }
   ],
   "source": [
    "%%expect TypeError\n",
    "\n",
    "print(\"I am \" + 25 + \" years old\")        ### Error: can only concatenate string"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ff6ed2f",
   "metadata": {},
   "source": [
    "### F-Strings \n",
    "\n",
    "**F-strings** (formatted string literals) are more readable and efficient for formatting strings in Python (available since Python 3.6). F-string is the preferred output method because it is clean and allows **expressions** between `{}`, so you don't need to worry about data types. Python f-strings use an **f** before the string and put expressions inside **{}**:\n",
    "\n",
    "`f\"{expression}\"`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2b91bc92",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "My name is Alice and I am 25 years old.\n",
      "The sum of 10 and 20 is 30\n"
     ]
    }
   ],
   "source": [
    "name = \"Alice\"\n",
    "age = 25\n",
    "print(f\"My name is {name} and I am {age} years old.\")   ### f-string with variables\n",
    "\n",
    "x = 10\n",
    "y = 20\n",
    "print(f\"The sum of {x} and {y} is {x + y}\")             ### f-string with expressions\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2962a01c",
   "metadata": {},
   "source": [
    "### `sep` and `end` Params\n",
    "\n",
    "The `print()` function has useful parameters: \n",
    "- `sep` for changing separator string in between print() arguments (default is space)\n",
    "- `end` for changing what comes at the end (default is newline)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6ddc5db8",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A B C  (separator is space by default)\n",
      "A-B-C\n",
      "2026/2/7\n"
     ]
    }
   ],
   "source": [
    "print(\"A\", \"B\", \"C\", \" (separator is space by default)\")   ### Output: A B C (separator is space by default)\n",
    "print(\"A\", \"B\", \"C\", sep=\"-\")   ### Output: A-B-C (separator changed to '-')\n",
    "print(2026, 2, 7, sep=\"/\")          ### Output: 2026/2/7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "dcc4f700-2231-4952-b787-fb47704bb3ea",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "1 2 3 "
     ]
    }
   ],
   "source": [
    "for num in range(1,4):\n",
    "    print(num)                  ### print list with default end character (\\n, new line)\n",
    "for num in range(1,4):\n",
    "    print(num, end=\" \")         ### Print list space as end character"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "12064b21",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Print \"hello, world\"\n",
    "### The output should look the same as the cell below\n",
    "### Your code starts here\n",
    "\n",
    "\n",
    "### Your code ends here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "75552105-2f26-4551-9616-cd03fc1646db",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello, world\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "print(\"hello, world\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a21b8435-1e58-4a26-98e3-6c5d08c40e6e",
   "metadata": {},
   "source": [
    "### Keyboard input\n",
    "\n",
    "Python provides a built-in function called `input` that stops the program and waits for the user to type something. When the user presses *Return* or *Enter*, the program resumes, and `input` returns what the user typed as a **string**. Before getting user input, you might want to display a **prompt** that explains what to type. The `input` syntax is:\n",
    "```\n",
    "variable = input(\"Prompt message: \")\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "807b54cc-d82e-4cdc-9123-1966faadb800",
   "metadata": {},
   "source": [
    "We usually save the user input value to a variable like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "8ae15203-5dc4-4926-9a97-2159c7f4a358",
   "metadata": {
    "tags": [
     "skip-execution"
    ]
   },
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter your username:  tychen\n"
     ]
    }
   ],
   "source": [
    "user_name = input(\"Enter your username: \")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2d6669ee-3b9b-4f6d-a8d2-3e03e6bf99c5",
   "metadata": {},
   "source": [
    "You can then use the variable. For example, in a print statement:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "122c37df-e9a8-442a-a13b-5fe2998f5278",
   "metadata": {
    "tags": [
     "skip-execution"
    ]
   },
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter your username:  tychen\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello,  tychen\n"
     ]
    }
   ],
   "source": [
    "user_name = input(\"Enter your username: \")\n",
    "print(\"Hello, \", user_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f94f0f0c-ffb8-49c7-a69c-7509084652b5",
   "metadata": {},
   "source": [
    "Or, to print richer information using `f-string`,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "acd1681b-c399-4e95-9750-0895b4cf9ddc",
   "metadata": {
    "tags": [
     "skip-execution"
    ]
   },
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter your age:  35\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "You are 35 years old.\n"
     ]
    }
   ],
   "source": [
    "### input() returns a string\n",
    "\n",
    "age = input(\"Enter your age: \")\n",
    "print(f\"You are {age} years old.\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0fa8808c-8d1a-459e-a233-8712d402f8d8",
   "metadata": {},
   "source": [
    "Note that the age you enter is a string, and it will need to be converted into a proper data type, such as `int`, before you can do arithmetic with it. See {ref}`type-conversion` later on this page."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63adcbbb",
   "metadata": {},
   "source": [
    "## Comments\n",
    "\n",
    "**Comments** are explanatory notes in your code that are ignored by the Python interpreter. Comments are used to: \n",
    "1. Explain complex logic: Help others (and your future self) understand what the code does; \n",
    "2. Document assumptions: Note why certain decisions were made; \n",
    "3. Mark **TODO** items: Indicate areas that need improvement or completion; and \n",
    "4. **Disable code temporarily**: Comment out code for testing without deleting it.\n",
    "\n",
    "Single-line comments start with the hash symbol `#`. Everything after `#` on that line is ignored by Python. For multi-line comments, we use multiple hashes. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "a9a51b86",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "### single-line comments\n",
    "# This is a comment explaining the code below\n",
    "price = 100\n",
    "tax_rate = 0.08  # 8% sales tax\n",
    "\n",
    "### multiple-line comments\n",
    "# Calculate total price including tax\n",
    "# total = price * (1 + tax_rate)\n",
    "# print(f\"Total price: ${total}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91633f0a",
   "metadata": {},
   "source": [
    "Ideally, good variable names can reduce the need for comments, but long names can make complex expressions hard to read, so there is a tradeoff. For example, `velocity_mph = 8` might be clear without a comment, but `v = 8 # velocity in miles per hour` might be more readable in a mathematical formula."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "ch02-syntax-comments-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Use Comments to Clarify a Calculation\n",
    "# Add comments that explain each step of the calculation.\n",
    "# Keep the code runnable and print exactly:\n",
    "# Use f-strings to format the output to two decimal places.\n",
    "price = 50\n",
    "tax_rate = 0.08\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "ch02-syntax-comments-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Final total: $54.00\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "price = 50\n",
    "tax_rate = 0.08\n",
    "\n",
    "# Calculate the tax for the order.\n",
    "tax = price * tax_rate\n",
    "\n",
    "# Add tax to the original price.\n",
    "final_total = price + tax\n",
    "\n",
    "print(f\"Final total: ${final_total:.2f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1e5d339-32c9-4267-96e2-3414ef486a22",
   "metadata": {},
   "source": [
    "## Variables\n",
    "\n",
    "A **variable** is a named location in computer memory that stores a value. Think of it as a **name**/label that is associated with some data. Variables allow us to store, retrieve, and manipulate data throughout the program. \n",
    "\n",
    "Unlike some other programming languages, Python doesn't require you to declare the **data type** when creating a variable. The type is automatically determined based on the value you assign (this is called **dynamic typing**) at runtime (execution)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec9d078a",
   "metadata": {},
   "source": [
    "### Creating Variables\n",
    "\n",
    "In Python, you create a variable by using an **assignment statement** with the assignment operator `=`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "34b95d94",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Alice is 25 years old.\n"
     ]
    }
   ],
   "source": [
    "name = \"Alice\"\n",
    "age = 25\n",
    "\n",
    "print(f\"{name} is {age} years old.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50d3c58b",
   "metadata": {},
   "source": [
    "Note that:\n",
    "1. Variables can be **reassign**ed.\n",
    "2. You can assign **multiple** values/expressions to multiple variables in one line."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "acf8a964",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello\n"
     ]
    }
   ],
   "source": [
    "### reassignment\n",
    "\n",
    "x = 10         # x is 10\n",
    "x = 20.5       # now x is 20.5\n",
    "x = \"hello\"    # now x is a string (type can change!)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "266f7d42",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "### multiple assignment in a single line:\n",
    "\n",
    "x = y = z = 0           # x, y, and z are all 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "f884fbd3",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "After swap: a = 20, b = 10\n"
     ]
    }
   ],
   "source": [
    "### swap values using tuple unpacking\n",
    "\n",
    "a, b, c = 10, 20, 30    # assign different values to variables\n",
    "a, b = b, a             # Swap values using tuple unpacking ==> sorting \n",
    "print(f\"After swap: a = {a}, b = {b}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "7834e76d",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Create a variable called \"name\" and use f-string to print it\n",
    "### The output should be the same as the cell below\n",
    "### Your code starts here\n",
    "\n",
    "\n",
    "### Your code ends here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "3e906f05",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, Dr. Chen\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "name = \"Dr. Chen\"\n",
    "print(f\"Hello, {name}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e29eefc",
   "metadata": {},
   "source": [
    "### Updating variables\n",
    "\n",
    "As you may have discovered, it is legal to make more than one assignment\n",
    "to the same variable.\n",
    "A new assignment makes an existing variable refer to a new value (and stop referring to the old value).\n",
    "\n",
    "For example, here is an initial assignment that creates a variable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "01fe9c58",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 5\n",
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9894bc22",
   "metadata": {},
   "source": [
    "And here is an assignment that changes the value of a variable."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "6d69107b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 7\n",
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "014f8f64",
   "metadata": {},
   "source": [
    "The following figure shows what these assignments look like in a state diagram."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "7716e7f6",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [],
   "source": [
    "from shared.diagram import make_rebind, draw_bindings\n",
    "\n",
    "bindings = make_rebind('x', [5, 7])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "71ffe70e",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAEoAAABRCAYAAAB1wTApAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjIsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvgI3uAAAAAAlwSFlzAAAPYQAAD2EBqD+naQAABUBJREFUeJztmtsrdFEUwJf7NSHkfqcwcilCkoRQkhLJA6VIefAHUArlD5AHKZcHcgm55laS6wORyYPQjHGX+50x+2vtIsX32cM35pxm/2oezrSPc/zO2mvWXvvoEUIIcL5E/+shHC5KDXhEMcJFMcJFMcJFMcJFMcJFMcJFMcJFMcJFMcJFMcJFMcJFMcJFMcJFMcJFMcJFMcJFMWIIOsLx8TE8PT29HVtbW4OlpSXz+Xq6srkQGhoKBwcHYGRkRI8rKiqguLj4/0fUzc0NPDw8gJ2dHT1WKpVwdHQELi4uIBZGR0epMI3mqIuLCwgPD4e1tTV6XFZWBrW1taBNtra2oLGxEaRSKdN4fNBXV1ffuxhRg+HhYRIYGEhaWlpIWFgYeXh4INrk+vqatLe3k+rqavL4+EiOj4/Jy8vLp2OTk5OJm5sbsbCwIMHBwWRpaUmta6mdo0pLS9+eoq+v76djZmZmQKFQgJeXF4SFhcHw8DA8Pj5CbGwsPhiYnZ0FExMTSEtLg+XlZZDJZODu7g6RkZEwNDQE9/f3EBMTQ/PJ9PQ0GBsbQ2pqKr3m5uYmODs70781ODgId3d3EBERQcc0NTXR6xcVFYGTk9On96ZSqehMaG9vf5sd/708uL6+hsnJSfD09IS5uTkQCufn57C6ukplm5qa/nOsvr4+5Ofnw8bGBn1ozKgTfrm5uaS8vJzI5XIaxuvr6x/G4HcNDQ3k6OiI/AYymYxUVlaSuro6cn9//+mY5+dnolAo6GdlZYVkZ2eTpKQkta7DLKqnp4ekpqYSpVJJj/v6+khKSgq9ifdcXl6S+vp6UlNTQ6RSKdE0mJu2trb+mpuQzc1N4uLiQlxdXYlEIiElJSU0n6mDRuqop6cnGBgYoDklOjoaEhMTaciLGY0VnIQQWFxchLGxMfDw8ICsrCywsLAAsaLxylwmk0F3dzcYGBhAdna2qArUX1/CXF1dQWdnJxweHtKSAAtXsfFraz2lUgkjIyO0bkJRWBcZGopnTf7ri+Ll5WVagDo6OtKpaGVlBWJAK92Dvb09OhVfXl5okscCVuhorc1ye3tLk7xcLoekpCSIiooCPT09ECpa7UepVCqYmJiA+fl5kEgkkJ6eTtdsQkQQjTupVAr9/f1gY2MDOTk5YGtrC0JDEKJeW7UdHR20G5CZmQn+/v4gJAQj6rWx1tvbS1f28fHxEBcXJ5i8JShRCN4O9qCmpqZoVGF0fdU60UlRr2BUYXSZm5vTvOXg4ADaRLCikLOzM5q3sDGXkZEBQUFBoC0ELUpILRvBi0LwFhcWFmB8fFxrLRtRiHrfsunq6qKL6d9u2YhKlDZbNqLrz1pZWUFBQQGEhITQ3IVbVtjCwRqstbUVLi8vNXJd0YlCcOrhuhA/Kysr0NzcTCt63OLHPUNNILqp96+WjZ+fH/11xO3+98keF9/7+/sfzsUcx1r5i16UQqGgLRvsQOzs7NDePO4yJyQkvI05OTmhO9av4K41TtXT01PmboV4erF/AUsGlIWYmZnR7Xicftjfwqoesbe3h93d3bdzqqqqaB9MnZaO6CNKpVLRiMGphdNwe3ubvnmTl5cHPj4+H8bjv+vt7Q1tbW20gGWG6BhjY2MkICBA7fNE+av3E/BNnMLCQrXPE/3UUwdM3riRgS+gqduN0KmIam1theTk5G+1bHRK1OjoKH3J7Dvo1NT7CToVUT+Bi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEi2KEiwI2/gB1AGuKa1VigAAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 54x61 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from shared.diagram import diagram, adjust\n",
    "\n",
    "width, height, x, y = [0.54, 0.61, 0.07, 0.45]\n",
    "ax = diagram(width, height)\n",
    "bbox = draw_bindings(bindings, ax, x, y)\n",
    "# adjust(x, y, bbox)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "db7f4db6",
   "metadata": {},
   "source": [
    "The dotted arrow indicates that `x` no longer refers to `5`.\n",
    "The solid arrow indicates that it now refers to `7`.\n",
    "\n",
    "A common kind of assignment is an **update**, where the new value of\n",
    "the variable depends on the old."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "38e705d1",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "x = 7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "c59351e7",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "8"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = x + 1\n",
    "x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53709e3b",
   "metadata": {},
   "source": [
    "This statement means \"get the current value of `x`, add one, and assign the result back to `x`.\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8eee20f4",
   "metadata": {},
   "source": [
    "Increasing the value of a variable is called an **increment**; decreasing the value is called a **decrement**.\n",
    "Because these operations are so common, Python provides **augmented assignment operators** that update a variable more concisely.\n",
    "For example, the `+=` operator increments a variable by the given amount."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "fc9b3d02",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z += 2\n",
    "z"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "939ec0e5",
   "metadata": {},
   "source": [
    "There are augmented assignment operators for the other arithmetic operators, including `-=` and `*=`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf233013-53c7-4b2c-bd5d-5fbd86374965",
   "metadata": {},
   "source": [
    "### Naming Rules & Conventions\n",
    "Variable names must follow these rules (from [PEP8](https://peps.python.org/pep-0008/)):\n",
    "\n",
    "1. Must start with a letter (a-z, A-Z) or underscore (`_`)\n",
    "2. Can contain **letters**, **digits** (0-9), and **underscores** (`_`)\n",
    "3. Can NOT contain spaces or special characters (@, #, $, %, etc.)\n",
    "4. Cannot be a Python **keyword** (like `if`, `for`, `class`, etc.)\n",
    "5. **Case-sensitive**: `Name`, `name`, and `NAME` are different variables\n",
    "\n",
    "Python programmers follow these **conventions** (recommended but not required):\n",
    "\n",
    "| Convention | Use Case | Example |\n",
    "|------------|----------|---------|\n",
    "| **snake_case** | Variable and function names | `student_name`, `total_price` |\n",
    "| UPPER_CASE | Constants | `MAX_SIZE`, `PI` |\n",
    "| PascalCase (not camelCase) | Class names | `StudentRecord`, `BankAccount` |\n",
    "| **Descriptive** names | Make code readable | `count` instead of `c` |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78b7679b-9bc0-490f-a93e-237290c1862a",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "## Built-in Data Types\n",
    "\n",
    "Python has **[standard types](https://docs.python.org/3/library/stdtypes.html)** built into the interpreter. The principal built-in types are: numerics, sequences, mappings, classes, instances, and exceptions. The commonly used data types can be organized as {numref}`python-data-types`.\n",
    "\n",
    "```{figure} ../../figures/python-data-types-2.png\n",
    "---\n",
    "width: 75%\n",
    "name: python-data-types\n",
    "---\n",
    "[Python Built-In Data Types](https://www.codecademy.com/article/what-are-python-data-types-and-how-to-check-them)\n",
    "```\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "b3b73ba0-3386-4818-a1ed-7e83d2f24e84",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "These types can be grouped into **simple**/**primitive** data types and [**collections**](https://docs.python.org/3/library/collections.html) types; namely, among the often-used built-in types, some are for storing **single values** (Literals), while others are for storing **multiple values**.\n",
    "\n",
    "| Group       | No.| Category      | Types                              | Remarks                          |\n",
    "|-------------|----|----|--------------------------------|-------------|\n",
    "| **Literals**    | 1  | Numeric       | **`int`**, **`float`**, `complex`          | Represent numbers (whole numbers, decimals, complex numbers) |\n",
    "|             | 2  | String | **`str`**                              | Represent text (immutable) |\n",
    "|             | 3  | Boolean       | **`bool`**                             | Represent True/False |\n",
    "|             | 4  | Null          | `NoneType`                         | Represent \"nothing\" |\n",
    "| **Collections** | 5  | **Sequence**      | **`list`**, **`tuple`**, **`range`**           | Ordered collections (list is mutable, tuple is immutable) |\n",
    "|             | 6  | Binary        | `bytes`, `bytearray`, `memoryview` | Store binary data |\n",
    "|             | 7  | Set           | _`set`_, `frozenset`                 | Unordered unique values (set is mutable, frozenset is immutable) |\n",
    "|             | 8  | Mapping       | **`dict`**                             | Key-value pairs for flexible data structure |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69c5038c-143f-45c5-b0de-21497dd224c0",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "In the examples below, we look at some examples of data types."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51a50799-124c-413b-8108-3ec8c106418e",
   "metadata": {},
   "source": [
    "### Numbers\n",
    "\n",
    "Python has three numeric types:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "301292ba",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Integer: 42\n",
      "Floating-point number: 3.14\n",
      "Complex number: (3+4j)\n"
     ]
    }
   ],
   "source": [
    "integer = 42             # integer (natural number)\n",
    "floating = 3.14          # floating-point number (real number)\n",
    "complex_num = 3 + 4j     # complex number\n",
    "\n",
    "print(f\"Integer: {integer}\")\n",
    "print(f\"Floating-point number: {floating}\")\n",
    "print(f\"Complex number: {complex_num}\") "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39cbf92f-c60a-4d21-b524-23230a06bfe1",
   "metadata": {},
   "source": [
    "### Strings (Text Data)\n",
    "\n",
    "\n",
    "Strings represent text (**character sequences**) and are created using quotes. Strings can be created using single or double quotes. You can also wrap a single quote in double quotes if you need to include a quote within the string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "6ae95f16-9cd6-43ce-8643-5c9bba310829",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Alice Alice Alice\n"
     ]
    }
   ],
   "source": [
    "name1 = \"Alice\"\n",
    "name2 = 'Alice'\n",
    "name3 = \"\"\"Alice\"\"\"\n",
    "print(name1, name2, name3)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "ef3de7c2-bd7e-447a-9b6e-8e85acf92257",
   "metadata": {},
   "source": [
    "Common string operations include:\n",
    "\n",
    "1. Concatenation: `\"Hello\" + \" \" + \"World\"` → `\"Hello World\"`\n",
    "2. Repetition: `\"Ha\" * 3` → `\"HaHaHa\"`. The multiplication (`*`) operator also works with strings; it makes multiple copies of a string and concatenates them.\n",
    "3. Length: `len(\"Python\")` → `6`. Python provides a useful function called `len` that computes the length of a string. Notice that `len` counts the letters between the quotes, but not the quotes. In collection types, `len` counts the number of elements in the collection.\n",
    "4. Indexing: `\"Python\"[0]` → `\"P\"`\n",
    "5. Slicing: `\"Python\"[0:3]` → `\"Pyt\"`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "40695490-f9b0-4228-9375-deecb9ece33a",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1. Hello, Alice!\n",
      "2. Hello, Alice!Hello, Alice!Hello, Alice!\n",
      "3. Length: 5\n",
      "4. First letter: A\n",
      "5. First three letters: Ali\n"
     ]
    }
   ],
   "source": [
    "name = \"Alice\"\n",
    "greeting = \"Hello, \" + name + \"!\"              ### 1. concatenation\n",
    "\n",
    "print(\"1.\", greeting)                           \n",
    "print(\"2.\", greeting * 3)                      ### 2. repetition\n",
    "print(f\"3. Length: {len(name)}\")               ### 3. length + f-string\n",
    "print(f\"4. First letter: {name[0]}\")           ### 4. indexing + f-string\n",
    "print(f\"5. First three letters: {name[0:3]}\")  ### 5. slicing + f-string"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "029492e0-97ac-467f-9e83-9b0a75567606",
   "metadata": {},
   "source": [
    "### Boolean Values\n",
    "\n",
    "Booleans represent truth values and are used extensively in conditional comparisons and logical expressions, which involve comparison/relational operators and logical operators."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "a8a72825-e790-4d67-b2c5-b5e6f9063ef8",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "3 > 5                 ### relational"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "37efbb3c-f75b-4d2f-b16f-858e8dbd775d",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2 > 1 and 3 > 2       ### logical"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "e4f0b204",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num1 is not greater than num2.\n"
     ]
    }
   ],
   "source": [
    "num1, num2, num3, num4 = 1, 2, 3, 4\n",
    "\n",
    "if (num1 > num2):                  ### comparison operator \">\"\n",
    "    print(\"num1 is greater than num2.\")\n",
    "else:\n",
    "    print(\"num1 is not greater than num2.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "225567f4",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "num1 > num2 and num3 > num4        ### logical operator \"and\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aff1c22b-092f-4918-bee2-f005801d056f",
   "metadata": {},
   "source": [
    "#### Truthy and Falsy\n",
    "\n",
    "In Python, every object has a truth value in Boolean contexts like `if` and `while`. \"Truthy\" values behave like `True`, while \"falsy\" values behave like `False` — empty containers and zero are falsy; most non-empty values are truthy.\n",
    "\n",
    "- Falsy: `False`, `None`, `0`, `0.0`, `''`, `[]`, `{}`, `set()`\n",
    "- Truthy: most other values (e.g., `'0'`, `[0]`).\n",
    "- Quick check: `bool(value)`; idiom: `if not items:` checks emptiness."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "ce0cb772",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "False\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "### truthy/falsy examples\n",
    "print(bool(0))         # False\n",
    "print(bool(''))        # False\n",
    "print(bool('0'))       # True\n",
    "print(bool([0]))       # True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "ch02-syntax-truthy-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Check Truthy and Falsy Values\n",
    "# Use bool() to print the truth value of each value.\n",
    "# Print exactly:\n",
    "# Empty cart: False\n",
    "# Cart with items: True\n",
    "# Zero quantity: False\n",
    "# Customer name: True\n",
    "empty_cart = []\n",
    "cart_items = [\"notebook\", \"pen\"]\n",
    "quantity = 0\n",
    "customer_name = \"Ava\"\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "ch02-syntax-truthy-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Empty cart: False\n",
      "Cart with items: True\n",
      "Zero quantity: False\n",
      "Customer name: True\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "empty_cart = []\n",
    "cart_items = [\"notebook\", \"pen\"]\n",
    "quantity = 0\n",
    "customer_name = \"Ava\"\n",
    "\n",
    "print(\"Empty cart:\", bool(empty_cart))\n",
    "print(\"Cart with items:\", bool(cart_items))\n",
    "print(\"Zero quantity:\", bool(quantity))\n",
    "print(\"Customer name:\", bool(customer_name))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0ec0fba3-ee36-4f04-a288-91c013e76eec",
   "metadata": {},
   "source": [
    "(type-conversion)=\n",
    "### Type conversion\n",
    "\n",
    "Type conversion is the general process of converting a value from one data type to another. There are two ways of type conversion to change type:\n",
    "*   **Type Casting**: Explicit conversion performed by the programmer (e.g., using `int(\"42\")`).\n",
    "*   **Type Coercion**: Implicit conversion performed automatically by the programming language (e.g., `3 + 4.5` results in `7.5`, where the integer `3` is coerced to a float to match the other operand)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "e2e4410e-bd1d-4642-960e-8cc215dba789",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num's type: <class 'int'>\n",
      "num's new type 5\n",
      "3 + 0.14 is 3.14 and has the type: <class 'float'>\n"
     ]
    }
   ],
   "source": [
    "### casting vs. coercion\n",
    "\n",
    "### type casting\n",
    "num = 5\n",
    "print(\"num's type:\", type(num))\n",
    "print(\"num's new type\", str(num))  ### casting (explicit conversion) by programmer\n",
    "\n",
    "### type coercion\n",
    "x = 3               ### integer\n",
    "y = 0.14            ### float\n",
    "print(f\"{x} + {y} is {x+y} and has the type: {type(x + y)}\")        \n",
    "                    ### int + float = float done automatically by Python interpreter\n",
    "                    ### coercion (implicit conversion)  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "625f0d8f",
   "metadata": {},
   "source": [
    "Casting matters for keyboard input: `input()` always returns a string, so you need to convert the value before doing arithmetic with it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a056ade",
   "metadata": {
    "tags": [
     "skip-execution"
    ]
   },
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter your age:  35\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "You will be 36 years old next year.\n"
     ]
    }
   ],
   "source": [
    "age = input(\"Enter your age: \")\n",
    "age = int(age)                        ### convert input string to integer\n",
    "print(f\"You will be {age + 1} years old next year.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "fe117174-faea-4dea-9b04-4bed01042684",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Convert Text Values\n",
    "# Convert text values from a form into useful Python values.\n",
    "# Also convert num_text into a float and add 1.0.\n",
    "# Print the converted values and their types exactly as shown below.\n",
    "# Quantity: 18 <class 'int'>\n",
    "# Price: 4.5 <class 'float'>\n",
    "# In stock: True <class 'bool'>\n",
    "# Num: 101.1 <class 'float'>\n",
    "quantity_text = \"18\"\n",
    "price_text = \"4.50\"\n",
    "in_stock_text = \"yes\"\n",
    "num_text = \"100.1\"\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "ff779492-9f42-4b3d-a662-05ab84d5acca",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Quantity: 18 <class 'int'>\n",
      "Price: 4.5 <class 'float'>\n",
      "In stock: True <class 'bool'>\n",
      "Num: 101.1 <class 'float'>\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "quantity_text = \"18\"\n",
    "price_text = \"4.50\"\n",
    "in_stock_text = \"yes\"\n",
    "num_text = \"100.1\"\n",
    "\n",
    "quantity = int(quantity_text)\n",
    "price = float(price_text)\n",
    "in_stock = in_stock_text == \"yes\"\n",
    "num = float(num_text) + 1.0\n",
    "\n",
    "print(\"Quantity:\", quantity, type(quantity))\n",
    "print(\"Price:\", price, type(price))\n",
    "print(\"In stock:\", in_stock, type(in_stock))\n",
    "print(\"Num:\", num, type(num))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ece60ee8-6ceb-41c8-88ac-28e1fb58adde",
   "metadata": {
    "vscode": {
     "languageId": "markdown"
    }
   },
   "source": [
    "### Type Hinting\n",
    "Type hinting/annotation in Python allows you to specify the expected data types of variables, function parameters, and return values, making your code more readable and easier to debug. Introduced in Python 3.5, type hints are optional and do not affect program execution, but they help tools like linters and IDEs catch type-related errors early. For example, you can annotate a function as `def add(a: int, b: int) -> int:` to indicate that both parameters and the return value should be integers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "aace507b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "num: int = 10               ### type hinting for integer\n",
    "name: str = \"Alice\"         ### type hinting for string\n",
    "is_active: bool = True      ### type hinting for boolean\n",
    "height: float = 5.9         ### type hinting for float"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4b947bb-3e17-4a4f-acbe-78d859998ab7",
   "metadata": {},
   "source": [
    "## Operators\n",
    "\n",
    "In programming languages, operators are special symbols that perform computations or logical comparisons between values. They form the backbone of most **expressions** — whether you’re performing arithmetic, comparing data, assigning values, or testing relationships between objects. (For a detailed discussion of Expressions and Operators, see [Python Reference/Expressions](https://docs.python.org/3/reference/expressions.html#))\n",
    "\n",
    "| Category | Operators | Description | Example |\n",
    "|----------|-----------|-------------|---------|\n",
    "| **Arithmetic** | `+` `-` `*` `/` `//` `%` `**` | Mathematical operations | `5 + 3`, `5 // 2`, `2 ** 3` |\n",
    "| **Comparison** | `==` `!=` `>` `<` `>=` `<=` | Compare values, return bool | `5 > 3`, `x == y` |\n",
    "| **Logical** | `and` `or` `not` | Boolean logic | `True and False`, `not True` |\n",
    "| **Assignment** | `=` `+=` `-=` `*=` `/=` `//=` `%=` `**=` | Assign and update values | `x = 5`, `x += 3` |\n",
    "| **Identity** | `is` `is not` | Test object identity | `x is None`, `a is not b` |\n",
    "| **Membership** | `in` `not in` | Test membership in sequence | `'a' in 'cat'`, `5 not in [1,2,3]` |\n",
    "| **Bitwise** | `&` `\\|` `^` `~` `<<` `>>` | Bit-level operations | `5 & 3`, `5 << 1` |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96e4063b",
   "metadata": {},
   "source": [
    "As an example for operators, we'll cover some operators here."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74379239-3cad-4570-b92f-0877923c35a3",
   "metadata": {},
   "source": [
    "### Arithmetic Operators\n",
    "\n",
    "An arithmetic operator is a symbol that represents an arithmetic computation. For example:\n",
    "\n",
    "1. The plus sign, `+`, performs addition.\n",
    "2. The minus sign, `-`, is the operator that performs subtraction. \n",
    "3. The asterisk, `*`,  performs multiplication. \n",
    "4. The forward slash, `/`, performs division. Note that in modern Python (Python 3+), the division operator `/` always returns a floating-point number, even if the result is a whole number.\n",
    "5. The integer/floor division operator, `//`, is called **floor division** because it always rounds down (toward the \"floor\").\n",
    "6. The **modulus operator** `%` returns the remainder after division.\n",
    "7. The operator `**` performs exponentiation; that is, it raises a\n",
    "number to a power. In other languages, such as R, MATLAB, Julia, and Excel, the caret `^` is used for exponentiation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "da801d92-5405-4806-9c59-45be4ddf8ac8",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "13\n",
      "7\n",
      "30\n",
      "3.3333333333333335\n",
      "3\n",
      "1\n",
      "1000\n"
     ]
    }
   ],
   "source": [
    "a = 10 + 3\n",
    "b = 10 - 3\n",
    "c = 10 * 3\n",
    "d = 10 / 3\n",
    "e = 10 // 3\n",
    "f = 10 % 3\n",
    "g = 10 ** 3\n",
    "\n",
    "print(a, b, c, d, e, f, g, sep=\"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb023b3e",
   "metadata": {},
   "source": [
    "### Integer division and modulus\n",
    "\n",
    "Recall that the **integer division operator**, `//`, divides two numbers and rounds down to an integer. For example, suppose the run time of a movie is 105 minutes. You might want to know how long that is in hours. \n",
    "\n",
    "Conventional division returns a floating-point number:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "8b336631",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.75"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "minutes = 105\n",
    "minutes / 60"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a341914",
   "metadata": {},
   "source": [
    "But we don't normally write hours with decimal points.\n",
    "Integer division returns the integer number of hours, rounding down:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "682c2550",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "minutes = 105\n",
    "hours = minutes // 60\n",
    "hours"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00b9ebbe",
   "metadata": {},
   "source": [
    "To get the remainder, you could subtract off one hour in minutes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "99a7b929",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "45"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "remainder = minutes - hours * 60\n",
    "remainder"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4d2cda3",
   "metadata": {},
   "source": [
    "Or you could use the **modulus operator**, `%`, which divides two numbers and returns the remainder."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "432f8057",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "45"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "remainder = minutes % 60\n",
    "remainder"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6731773d",
   "metadata": {},
   "source": [
    "The modulus operator is more useful than it might seem.\n",
    "For example, it can check whether one number is divisible by another -- if `x % y` is zero, then `x` is divisible by `y`.\n",
    "\n",
    "Also, it can extract the right-most digit or digits from a number.\n",
    "For example, `x % 10` yields the right-most digit of `x` (in base 10).\n",
    "Similarly, `x % 100` yields the last two digits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "93ac8c58",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 123\n",
    "x % 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "b11baa81",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "23"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x % 100"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22fe7114",
   "metadata": {},
   "source": [
    "Finally, the modulus operator can do \"clock arithmetic\".\n",
    "For example, if an event starts at 11 AM and lasts three hours, we can use the modulus operator to figure out what time it ends."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "9084d1f4",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "start = 11\n",
    "duration = 3\n",
    "end = (start + duration) % 12\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "892ecc40",
   "metadata": {},
   "source": [
    "The event would end at 2 PM."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47d7facb-e3a1-4648-91e0-f7b4e29df7a9",
   "metadata": {},
   "source": [
    "### Operator Precedence\n",
    "\n",
    "Operator precedence determines the order in which operations are evaluated in an expression. Operations with higher precedence are performed before those with lower precedence. When in doubt, use the parentheses `()` to ensure you have the preferred precedence.\n",
    "\n",
    "Notice that exponentiation happens before addition because exponentiation is the 2nd highest precedence. This actually follows the order of operations you might have learned in a math class: exponentiation happens before multiplication and division, which happen before addition and subtraction."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd30b279-d809-400c-8eff-14ecf698d0c3",
   "metadata": {},
   "source": [
    "In the following example, multiplication happens before addition, and exponentiation happens before multiplication. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "4d431206",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19\n"
     ]
    }
   ],
   "source": [
    "num1 = 12 + 5 * 6\n",
    "num2 = (12 + 5) * 6\n",
    "\n",
    "x, y, z = 1, 2, 3\n",
    "\n",
    "result = x + y * z ** 2\n",
    "print(result)               ### output: 13"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "ch02-syntax-operators-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Pack Orders with Operators\n",
    "# A warehouse packs items into boxes of 12.\n",
    "# Use integer division and modulus to calculate full boxes and leftover items.\n",
    "# Print exactly:\n",
    "# Full boxes: 7\n",
    "# Leftover items: 5\n",
    "items = 89\n",
    "box_size = 12\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "ch02-syntax-operators-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Full boxes: 7\n",
      "Leftover items: 5\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "items = 89\n",
    "box_size = 12\n",
    "\n",
    "full_boxes = items // box_size\n",
    "leftover_items = items % box_size\n",
    "\n",
    "print(\"Full boxes:\", full_boxes)\n",
    "print(\"Leftover items:\", leftover_items)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0892cb9-dd30-4b8b-a181-520f2ecc7766",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "```{index} keywords\n",
    "```\n",
    "## Python Keywords \n",
    "\n",
    "Reserved words, or keywords, are special words reserved by the programming language to be used to specify the **structure** of a program. Keywords of the language cannot be used as ordinary identifiers. For example, if you try to assign a string to a variable name _class_, since `class` is a **keyword**, you will receive a syntax error because the Python interpreter will detect that. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "82d88b34-bb2e-409a-a846-225fb63a47ab",
   "metadata": {},
   "source": [
    "For example, this code is intentionally invalid because `class` is a Python keyword:\n",
    "\n",
    "```text\n",
    "class = 'Self-Defense Against Fresh Fruit'\n",
    "```\n",
    "\n",
    "Python reports this as a syntax error before the program can run:\n",
    "\n",
    "```text\n",
    "SyntaxError: invalid syntax\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84971843",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "Here's a complete list of [35 Python keywords](https://docs.python.org/3/reference/lexical_analysis.html#keywords) as shown in the [Python Language Reference](https://docs.python.org/3.13/reference/index.html):\n",
    "```\n",
    "False      await      else       import     pass\n",
    "None       break      except     in         raise\n",
    "True       class      finally    is         return\n",
    "and        continue   for        lambda     try\n",
    "as         def        from       nonlocal   while\n",
    "assert     del        global     not        with\n",
    "async      elif       if         or         yield\n",
    "```\n",
    "\n",
    "Keywords serve as the **grammar glue** for you to express structure and can be grouped as follows:\n",
    "\n",
    "| Structure | Keywords |\n",
    "|---|---|\n",
    "| 1. Control flow | `if`, `elif`, `else`, `for`, `while`, `break`, `continue`, `pass` |\n",
    "| 2. Logic/conditions | `and`, `or`, `not`, `is`, `in` |\n",
    "| 3. Definitions | `def`, `class`, `lambda`, `return`, `yield` |\n",
    "| 4. Exception handling | `try`, `except`, `finally`, `raise`, `assert` |\n",
    "| 5. Imports/modules | `import`, `from`, `as` |\n",
    "| 6. Scope | `global`, `nonlocal`, `del` |\n",
    "| 7. Async | `async`, `await` |\n",
    "| 8. Context managers | `with` |\n",
    "| 9. Constants/values | `True`, `False`, `None` |\n",
    "\n",
    "You don't have to memorize this list, but you can already see how these keywords play a critical role in formulating code. In most development environments, keywords are displayed in a different color; if you try to use one as a variable name, you'll be alarmed not to."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "ff996be3",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Positive number\n"
     ]
    }
   ],
   "source": [
    "### example of the \"if\" keyword in Python\n",
    "num = 5\n",
    "if num > 0:\n",
    "    print(\"Positive number\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "a0772741",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "2\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "### example of the \"for\" keyword in Python\n",
    "for i in range(5):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "807bdb9f",
   "metadata": {},
   "source": [
    "### Soft keywords\n",
    "\n",
    "Python's soft keywords are special words that act as keywords only within specific contexts, but can be used as regular identifiers (like variable or function names) in other contexts. As of Python 3.12, there are 4 [soft keywords](https://docs.python.org/3.13/reference/lexical_analysis.html#soft-keywords): **match**, **case**, **_**, and **type** "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "ch02-syntax-keywords-exercise-q",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "False\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "# Import the keyword module to check whether \n",
    "# note \"match\" and \"type\" are soft keywords.\n",
    "import keyword\n",
    "words = [\"for\", \"customer_total\", \"match\", \"type\"]\n",
    "print(keyword.iskeyword(words[0]))\n",
    "print(keyword.iskeyword(words[1]))\n",
    "print(keyword.iskeyword(words[2])) \n",
    "print(keyword.iskeyword(words[3]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69d805d0",
   "metadata": {},
   "source": [
    "## Data Structures\n",
    "\n",
    "Python’s [data structure](https://docs.python.org/3/tutorial/datastructures.html) are the built‑in **`container`** types you use to store, organize, and operate on groups of items/values. The four main data structure types are: `list`, `tuple`, `dictionary`, and `set`. \n",
    "\n",
    "The commonly used **built-in**/**standard** data structures can be grouped as: \n",
    "- Sequence Types\n",
    "- Set Types\n",
    "- Mapping Types\n",
    "\n",
    "```\n",
    "Collections (broad category)\n",
    "├── Sequence Types (ordered, indexed)\n",
    "│   ├── list\n",
    "│   ├── tuple\n",
    "│   ├── str (string)\n",
    "│   ├── range\n",
    "│   └── bytes/bytearray\n",
    "│\n",
    "├── Set Types (unordered, no duplicates)\n",
    "│   ├── set\n",
    "│   └── frozenset\n",
    "│\n",
    "└── Mapping Types (key-value pairs)\n",
    "    └── dict\n",
    "```\n",
    "\n",
    "Among them, `list`, `tuple`, and `range` are [sequence types](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range). Also, `strings` are considered a sequence type (a kind of collection) because they behave like collections of characters, although conceptually, in many languages other than Python, strings are considered primitives, not collections.\n",
    "\n",
    "`range` is debatable as a “collection”; it’s really a lazy sequence generator, not a traditional data structure. It does like a sequence, so Python treats it as one. Note that `range` stores a formula, not data; it computes values on demand. Therefore, `range` is a sequence protocol implementer, not a data container.\n",
    "\n",
    "A `set` object is an \"unordered collection of distinct hashable objects. Common uses include membership testing, removing duplicates from a sequence, and computing mathematical operations such as intersection, union, difference, and symmetric difference\" [cite:p`Python Standard Library_2026`].\n",
    "\n",
    "Mapping in Python refers to data types that store **key-value** pairs, where each key is associated with a corresponding value. The most common mapping type is the dictionary (`dict`).\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99385ba6",
   "metadata": {},
   "source": [
    "Mutability and order are two important characteristics of Python data structures, summarized in the table below. \n",
    "\n",
    "| Type | Literal | `Mutable` | Ordered | Usage |\n",
    "|------|---------|---------|---------|-------|\n",
    "| **Sequence Types** | | | | |\n",
    "| list | `[1, 2, 3]` | Yes | Yes | General purpose; dynamic arrays; index/slice access. |\n",
    "| tuple | `(1, 2, 3)` | No | Yes | Fixed records; function returns; hashable if elements are.* |\n",
    "| range | `range(10)` | No | Yes | Memory-efficient integer sequences; iteration. |\n",
    "| str | `\"hi\"` | No | Yes | Text; immutable character sequences. |\n",
    "| **Set Types** | | | | |\n",
    "| set | `{1, 2, 3}` | Yes | No | Unique items; membership testing; set operations. |\n",
    "| frozenset | `frozenset({1,2})` | No | No | Immutable set; dict keys; set elements. |\n",
    "| **Mapping Types** | | | | |\n",
    "| dict | `{\"a\": 1, \"b\": 2}` | Yes | Yes** | Key-value lookups; counting; grouping; configuration. |\n",
    "\n",
    "**Notes:**\n",
    "- \\* Tuples are hashable only if all elements are hashable.\n",
    "- \\*\\* Dict ordering guaranteed in Python 3.7+.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "126d4c02",
   "metadata": {},
   "source": [
    "Python data collections let you: \n",
    "- model data naturally (ordered records, lookup tables, unique elements), \n",
    "- support iteration and common algorithms, \n",
    "- use methods for adding, removing, searching, and\n",
    "- transforming data.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b85e2a5-6a30-4213-a7d8-e8c45809f796",
   "metadata": {},
   "source": [
    "### Lists (Ordered Collections)\n",
    "\n",
    "Lists store **multiple** items in **order** and are **mutable** (can be changed):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "05eade53",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Numbers: [1, 2, 3, 4, 5]\n",
      "Fruits: ['Apple', 'Banana', 'Cherry']\n",
      "Mixed: [1, 'hello', 3.14, True]\n",
      "Empty list: []\n"
     ]
    }
   ],
   "source": [
    "numbers = [1, 2, 3, 4, 5]\n",
    "fruits = [\"Apple\", \"Banana\", \"Cherry\"]\n",
    "mixed = [1, \"hello\", 3.14, True]\n",
    "empty_list = []\n",
    "\n",
    "print(f\"Numbers: {numbers}\")\n",
    "print(f\"Fruits: {fruits}\")\n",
    "print(f\"Mixed: {mixed}\")\n",
    "print(f\"Empty list: {empty_list}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4027218",
   "metadata": {},
   "source": [
    "Common list operations:\n",
    "1. Append: `numbers.append(6)` → `[1, 2, 3, 4, 5, 6]`\n",
    "2. **Access/Indexing**: `numbers[0]` → `1`\n",
    "3. **Slicing**: `numbers[1:3]` → `[2, 3]`\n",
    "4. Length: `len(numbers)` → `5`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "5971bdbc-8854-4420-b001-a8db8e9c8dad",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3, 4, 5]\n",
      "[1, 2, 3, 4, 5, 7]\n"
     ]
    }
   ],
   "source": [
    "### run the previous code cell first to define the lists before running this cell\n",
    "### append() method: add an element to the end of the list\n",
    "print(numbers)          ### before append()\n",
    "numbers.append(7)          ### append(); mutable: update/change the list\n",
    "print(numbers)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "e420309a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3, 4, 5]\n",
      "1\n",
      "3\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "### indexing\n",
    "numbers = [1, 2, 3, 4, 5]\n",
    "print(numbers)\n",
    "print(numbers[0])        ### indexing\n",
    "print(numbers[2])        ### indexing\n",
    "print(numbers[-1])       ### indexing (last element)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "ed0a2f10",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3, 4, 5]\n",
      "[1, 2]\n",
      "[1, 2, 3, 4, 5]\n",
      "[1, 2, 3, 4]\n",
      "[1, 3, 5]\n",
      "[1, 3, 5]\n"
     ]
    }
   ],
   "source": [
    "### slicing\n",
    "print(numbers)\n",
    "print(numbers[0:2])       ### slicing\n",
    "print(numbers[0:])        ### slicing (all elements)\n",
    "print(numbers[:-1])       ### slicing (all elements except the last one)\n",
    "print(numbers[::2])      ### slicing (every second element)\n",
    "print(numbers[0::2])      ### slicing (every second element)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "83d65728",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n"
     ]
    }
   ],
   "source": [
    "### length\n",
    "numbers = [1, 2, 3, 4, 5]\n",
    "print(len(numbers))      ### length"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "13dad8d6",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "After modification: ['Apple', 'Banana', 'cranberry']\n"
     ]
    }
   ],
   "source": [
    "fruits[2] = \"cranberry\"                     ### lists are mutable: modify an element\n",
    "print(f\"After modification: {fruits}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02b5bc24-d197-4db7-b077-5be508afff35",
   "metadata": {},
   "source": [
    "### Tuples (Immutable Sequences)\n",
    "\n",
    "Tuples are similar to lists, but they cannot be changed after creation (**immutable**). So, use tuples when you want to ensure data won't change:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3de65cd",
   "metadata": {},
   "source": [
    "rgb_color = (255, 128, 0)\n",
    "single = (42,)             # Note the comma for single-item tuple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "52ffca14-8329-4dc4-b7a0-e322a59a461f",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Converted to tuple: ('Apple', 'Banana', 'cranberry')\n",
      "first element in coordinate:  Apple\n"
     ]
    }
   ],
   "source": [
    "fruits = tuple(fruits)\n",
    "print(f\"\\nConverted to tuple: {fruits}\")            ### ( )\n",
    "print(\"first element in coordinate: \", fruits[0])   ### indexing"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4eb93443",
   "metadata": {},
   "source": [
    "Since tuples are immutable, the following operation would generate an error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "449cbfdb-d110-4b2e-97c8-b138a2794f6b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'tuple' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[31mTypeError\u001b[39m\u001b[31m:\u001b[39m 'tuple' object does not support item assignment\n"
     ]
    }
   ],
   "source": [
    "%%expect TypeError\n",
    "\n",
    "fruits[2] = \"cherry\"  # This would cause an error because tuples are immutable!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "90a106a2-af97-4842-8731-2083524b505a",
   "metadata": {},
   "source": [
    "### Dictionaries (Key-Value Pairs)\n",
    "\n",
    "In Python, a mapping type is a collection that stores data as `key–value` pairs, where each key is unique and maps to a corresponding value. The most common mapping type is the **`dictionary`** (`dict`), which allows flexible data organization and fast lookup, insertion, and modification of values by key rather than numerical index. An example of a Python dictionary: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "bd265a1b",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'name': 'Alice', 'age': 20, 'major': 'IST'}"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "student = {\n",
    "    \"name\": \"Alice\",\n",
    "    \"age\": 20,\n",
    "    \"major\": \"IST\"\n",
    "}\n",
    "student"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c456df76",
   "metadata": {},
   "source": [
    "Common dictionary operations:\n",
    "1. **Access**: `student[\"name\"]` → `\"Alice\"`\n",
    "2. Add/Update: `student[\"gpa\"] = 3.8`\n",
    "3. **Keys**: `student.keys()` → `dict_keys(['name', 'age', 'major'])`\n",
    "4. **Values**: `student.values()` → `dict_values(['Alice', 20, 'Computer Science'])`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "b94e735a",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Student Name: Alice\n",
      "student: {'name': 'Alice', 'age': 20, 'major': 'CS', 'GPA': 3.5}\n",
      "dict_keys(['name', 'age', 'major', 'GPA'])\n",
      "dict_values(['Alice', 20, 'CS', 3.5])\n"
     ]
    }
   ],
   "source": [
    "print(f\"Student Name: {student['name']}\")   ### 1. access value by key\n",
    "student[\"major\"] = \"CS\"                     ### 2. update: MUTABLE\n",
    "student[\"GPA\"] = 3.5                        ### 2. add new key-value pair: MUTABLE\n",
    "print(f\"student: {student}\")\n",
    "\n",
    "print(student.keys())                       ### 3. keys\n",
    "print(student.values())                     ### 4. values"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6ce736f-4fae-4c7f-b386-e508a62f7d00",
   "metadata": {},
   "source": [
    "### Objects, references, and mutability"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96f391e9-261a-4cee-9326-38f2ddcc5c10",
   "metadata": {},
   "source": [
    "#### Type checking\n",
    "\n",
    "The built-in function `type()` returns the data type of the object; in this case, variables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "e1a3b4ae",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'int'>\n",
      "<class 'float'>\n",
      "<class 'str'>\n",
      "<class 'list'>\n"
     ]
    }
   ],
   "source": [
    "num1 = 10                   ### integer\n",
    "num2 = 10.1                 ### floating-point number\n",
    "greeting = \"hello, world\"   ### text/string\n",
    "fruits = ['Apple', 'Banana', 'Cherry']      ### lists are enclosed with square brackets\n",
    "\n",
    "print(type(num1))\n",
    "print(type(num2))\n",
    "print(type(greeting))\n",
    "print(type(fruits))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73b6a4ca-d517-4536-ae0f-b9ae75e6399e",
   "metadata": {},
   "source": [
    "#### Object ID\n",
    "In Python, every object has a unique identity, which can be obtained using the built-in `id()` function. An identity is a unique integer that remains constant for an object throughout its lifetime. This is useful for understanding how Python manages objects in memory and for distinguishing between objects that have the same value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "d90905d1-d46c-4af6-9fda-b932461bd61f",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4315439072\n",
      "4454165680\n",
      "4455960560\n",
      "4450821504\n"
     ]
    }
   ],
   "source": [
    "print(id(num1))\n",
    "print(id(num2))\n",
    "print(id(greeting))\n",
    "print(id(fruits))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "ch02-syntax-structures-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Choose Data Structures\n",
    "# Create a list, tuple, and dictionary for a small sales record.\n",
    "# Print exactly:\n",
    "# Regions: ['North', 'South', 'West']\n",
    "# Quarter: (2026, 'Q1')\n",
    "# West sales: 4100\n",
    "\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "ch02-syntax-structures-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Regions: ['North', 'South', 'West']\n",
      "Quarter: (2026, 'Q1')\n",
      "West sales: 4100\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "regions = [\"North\", \"South\", \"West\"]\n",
    "quarter = (2026, \"Q1\")\n",
    "sales = {\"North\": 3200, \"South\": 2850, \"West\": 4100}\n",
    "\n",
    "print(\"Regions:\", regions)\n",
    "print(\"Quarter:\", quarter)\n",
    "print(\"West sales:\", sales[\"West\"])"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "5ba3a79a-97fc-40f6-b682-068cb0b55fce",
   "metadata": {},
   "source": [
    "## Modules and Packages\n",
    "\n",
    "In Python, functions, classes, modules, packages, and libraries are essential tools for organizing and reusing code: \n",
    "- A function is a named block of code that performs a specific task and can be called whenever needed. \n",
    "- A class is a blueprint for creating objects that encapsulate data and behavior (methods/functions) together, supporting object-oriented programming.\n",
    "- Modules are files containing Python code—such as functions, classes, or variables—that can be imported into other programs. \n",
    "- Packages are collections of modules organized in directories, making it easier to structure larger projects. \n",
    "- Libraries are collections of related modules and packages that provide ready-to-use solutions for common programming tasks, such as data analysis, web development, or scientific computing. \n",
    "\n",
    "Together, these components help make Python code more organized, efficient, and maintainable. \n",
    "\n",
    "Note that a **module** is a single Python file (e.g., `calc.py`) and a **Package**: a directory/folder containing modules (optionally with `__init__.py`). So:\n",
    "\n",
    "- **Module**: a single Python file (e.g., `mymodule.py`).\n",
    "- **Package**: a directory of modules (optionally with `__init__.py`)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45804ce3-a6e9-433f-a621-e88d53af253d",
   "metadata": {},
   "source": [
    "**Import patterns (when to use):**\n",
    "- `import math` → use `math.sqrt(25)`; clear, namespaced imports.\n",
    "- `from math import sqrt` → use `sqrt(25)`; convenient but use sparingly for readability.\n",
    "- `import math as m` → use `m.pi`; alias for brevity (common with large libs).\n",
    "\n",
    "**Installing external packages (Notebooks):**\n",
    "- Use `%pip install package_name` to install into the active kernel; if imports fail, restart the kernel.\n",
    "- For projects, prefer a virtual environment (e.g., `python -m venv .venv`) **activated**.\n",
    "\n",
    "**Style notes:** Prefer absolute imports in top-level scripts; reserve relative imports for package internals. Follow PEP 8 import order: standard library → third-party → local.\n",
    "\n",
    "Common data-science aliases (for later chapters): `numpy as np`, `pandas as pd`, `matplotlib.pyplot as plt`. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53f4017d",
   "metadata": {},
   "source": [
    "Python has about 300 built-in modules as part of the standard library that are shipped with Python. For those modules, you just import and use them (e.g., import math). There are different ways of importing:\n",
    "\n",
    "| Import Pattern            | Example Code           | Usage Example         | Description                                 |\n",
    "|--------------------------|-----------------------|----------------------|---------------------------------------------|\n",
    "| Standard import          | `import math`         | `math.sqrt(25)`      | Clear, namespaced imports                   |\n",
    "| Selective import         | `from math import sqrt`| `sqrt(25)`           | Convenient, but use sparingly for readability|\n",
    "| Import all (not recommended) | `from math import *` | `sqrt(25)`           | Imports all names; can cause name conflicts and is discouraged |\n",
    "| Aliased import           | `import math as m`    | `m.pi`               | Alias for brevity (common with large libs)  |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d508d7b5-ed4f-459c-b131-10d33db45393",
   "metadata": {},
   "source": [
    "To use a variable/attribute in a module, you have to use the **dot operator** (`.`) between the name of the module and the name of the variable. For example, the Python math module provides a variable called `pi` that contains the value of the mathematical constant denoted $\\pi$. We can display its value like `math.pi`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "96a15bac",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5.0"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import math\n",
    "math.sqrt(25)     ### dot operator"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37fa8b7a",
   "metadata": {},
   "source": [
    "**External Package Notes**\n",
    "\n",
    "Python external (third-party) modules created by the community. You must use `pip` to install them first (e.g., notebook, NumPy, pandas, ...), then import them to use. Most software on the Python Package Index (PyPI; https://pypi.org, where `pip` accesses software packages) is referred to as \"packages\" in this context. \n",
    "\n",
    "To install the packages in the CLI, you would go into your project directory, activate your virtual environment, and then use the `pip` installation syntax to install the package into your `.venv` folder (site-packages) for dependency integrity: \n",
    "\n",
    "`pip install [package_name]` \n",
    "\n",
    "If you are in Jupyter Notebook, use the Jupyter Notebook magic command `%pip` (instead of the older !pip) to achieve the same:\n",
    "\n",
    "`%pip install [package_name]` "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3822da3d",
   "metadata": {},
   "source": [
    "For example, NumPy (numeric Python) is a popular package for data science and we can install it from inside Jupyter Notebook:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "af7f5a7e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# %pip install numpy"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20baba54",
   "metadata": {},
   "source": [
    "If you have installed the package already, you would want to comment it out:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4df36c04",
   "metadata": {
    "tags": []
   },
   "source": [
    "`%pip install numpy`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "id": "ch02-syntax-modules-exercise-q",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Use a Standard Library Module\n",
    "# Use the math module to calculate how many vans are needed.\n",
    "# Each van can carry 15 boxes.\n",
    "# Print exactly:\n",
    "# Vans needed: 6\n",
    "boxes = 82\n",
    "van_capacity = 15\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "ch02-syntax-modules-exercise-a",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Vans needed: 6\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "import math\n",
    "\n",
    "boxes = 82\n",
    "van_capacity = 15\n",
    "\n",
    "vans_needed = math.ceil(boxes / van_capacity)\n",
    "\n",
    "print(\"Vans needed:\", vans_needed)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.13"
  },
  "metadata": {
   "tags": []
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
