{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d0286422",
   "metadata": {},
   "source": [
    "# Built-in Types and Functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "9e983a2b",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input"
    ]
   },
   "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, download, structshape\n",
    "\n",
    "# Register as top-level modules so direct imports work in subsequent cells\n",
    "sys.modules['thinkpython'] = thinkpython\n",
    "sys.modules['diagram'] = diagram\n",
    "sys.modules['jupyturtle'] = jupyturtle\n",
    "sys.modules['download'] = download\n",
    "sys.modules['structshape'] = structshape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e7216c6",
   "metadata": {},
   "source": [
    "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",
    "This chapter builds upon the variables and data types introduced earlier, providing deeper coverage of Python's type system and advanced operations. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07cb0a00",
   "metadata": {},
   "source": [
    "## About Types\n",
    "Python is dynamically typed, which means you don't have to declare the data type when creating a variable. The interpreter will figure it out at run time. For example, the `x` below will receive proper types without user intervention. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fd7f1e76",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 10\n",
    "x = \"hello\"\n",
    "x = [1, 2, 3, ]\n",
    "x[0] = \"M S&T\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "108ad891",
   "metadata": {},
   "source": [
    "A kind of value is called a **type**. Actually, **every value has a type** -- or we sometimes say it \"belongs to\" a type. Python provides a function called `type()` that tells you the type of any value. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1e0b3514",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'int'>\n",
      "<class 'float'>\n",
      "<class 'float'>\n",
      "<class 'str'>\n",
      "<class 'str'>\n"
     ]
    }
   ],
   "source": [
    "a = type(1)\n",
    "b = type(2.0)\n",
    "c = type(3/2)\n",
    "d = type('Hello, World!')\n",
    "e = type('126')       ### note this is a string, not a number\n",
    "\n",
    "print(a, b, c, d, e, sep='\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "97d3798f",
   "metadata": {},
   "source": [
    "`type` and the built-in function **`isinstance()`** work similarly, except `isinstance()` allows you to check the type you assume and returns True or False. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bc149908",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "print(isinstance(1, int))\n",
    "print(isinstance('126', str))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da671652",
   "metadata": {},
   "source": [
    "### Common Built-in 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 table below.\n",
    "\n",
    "In the Python **standard library**, they are grouped into 8 categories: \n",
    "\n",
    "| Group      | No.| Category      | Types                              | Remarks                                           | Sample Use Case |\n",
    "|------------|----|---------------|------------------------------------|---------------------------------------------------|------------------|\n",
    "| Literals   | 1  | Numeric       | `int`, `float`, `complex`          | Numbers for mathematical operations               | Counts, indices, ages, prices, measurements |\n",
    "|            | 2  | Text sequence | `str`                              | Text and character data                           | Names, messages, file paths |\n",
    "|            | 3  | Boolean       | `bool`                             | Logical values (True/False)                       | Flags, conditions, toggle states |\n",
    "|            | 4  | **Null**          | `NoneType`                         | Represents absence of value                       | Absence of value, default state |\n",
    "| Collections| 5  | Sequence      | `list`, `tuple`, `range`           | **Ordered collections** of items                  | Shopping cart items, student grades, coordinates, RGB colors |\n",
    "|            | 6  | Binary        | `bytes`, `bytearray`, `memoryview` | Binary data and memory manipulation               | Image data, encrypted content |\n",
    "|            | 7  | Set           | `set`, `frozenset`                 | **Unordered collections** of unique items         | Removing duplicates, membership testing |\n",
    "|            | 8  | Mapping       | `dict`                             | **Key-value** pairs                               | User profiles, configuration settings |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "11e62208",
   "metadata": {},
   "source": [
    "```{figure} ../../images/python-data-types-2.png\n",
    "---\n",
    "width: 500px\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",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9643a183",
   "metadata": {},
   "source": [
    "### Type Hierarchy\n",
    "\n",
    "The [standard type hierarchy](https://docs.python.org/3.14/reference/datamodel.html#the-standard-type-hierarchy) in the [Python Language Reference](https://docs.python.org/3.14/reference/index.html) lists 8 different built-in data types with a slightly different categorization:\n",
    "\n",
    "| No.| Category      | Type(s)                            | Remarks                                           |\n",
    "|----|---------------|------------------------------------|---------------------------------------------------|\n",
    "| 1  | Null          | `NoneType`                         | `None`, represents absence of value                       |\n",
    "| 2  | NotImplemented| `NotImplementedType`               | `NotImplemented`, a built-in constant indicating that an operation is not implemented for a particular type combination               |\n",
    "| 3  | Ellipsis      |  `Ellipsis`                        | `...`, a placeholder, explicitly signals intentional incompleteness               |\n",
    "| 4  | Numeric       | integers (`int` and `bool`), `float`, `complex`  | Numbers for mathematical operations and Boolean (`True`/`False`)              |\n",
    "| 5  | Sequence      | `str`, `tuple`, `bytes `           | **immutable**; **ordered** , **indexed**, and **slicible** collections of items; support slicing   |\n",
    "|    |               | `list`, `bytearray`                | **mutable**; ordered, indexed, and slicible collections of items |\n",
    "| 6  | Set           | `set`, `frozenset`                 | Unordered collections of unique items; `set` is mutable and `frozenset` is not        |\n",
    "| 7  | Mapping       | `dict`                             | **Key-value** pairs                               |\n",
    "| 8  | Callable      | User-defined functions             |                            |\n",
    "|    |               | Instance methods                   |               |\n",
    "|    |               | Generator functions                |                |\n",
    "|    |               | Coroutine functions                |                |\n",
    "|    |               | Asynchronous generator functions                |                |\n",
    "|    |               | Built-in functions                 |                |\n",
    "|    |               | Built-in methods                   |                |\n",
    "|    |               | Classes                   |                |\n",
    "|    |               | Class Instances                   |                |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b508f3f3",
   "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": null,
   "id": "f4ef84f1",
   "metadata": {},
   "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": "0262b215",
   "metadata": {},
   "source": [
    "### 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) is performed by the programmer (e.g., using `int(\"42\")`) using the **type constructors**.\n",
    "*   **Type Coercion** (implicit conversion) is performed automatically by the Python interpreter (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": "markdown",
   "id": "4c6b4b64",
   "metadata": {},
   "source": [
    "#### Type Constructors\n",
    "\n",
    "Core Python types that are also constructor functions include:\n",
    "\n",
    "| Function  | Converts To              | Example                             | Explanation                                           |\n",
    "| --------- | ------------------------ | ----------------------------------- | ----------------------------------------------------- |\n",
    "| `int()`   | Integer                  | `int(\"10\") → 10`                    | Converts string \"10\" to integer 10                    |\n",
    "| `float()` | Floating-point number    | `float(\"3.14\") → 3.14`              | Converts string \"3.14\" to floating-point 3.14         |\n",
    "| `str()`   | String                   | `str(25) → \"25\"`                    | Converts integer 25 to string \"25\"                    |\n",
    "| `bool()`  | Boolean (`True`/`False`) | `bool(0) → False`, `bool(5) → True` | **0 converts to False**, **non-zero values convert to True**  |\n",
    "| `list()`  | List                     | `list(\"abc\") → ['a','b','c']`       | Converts **string into list of individual characters**    |\n",
    "| `tuple()` | Tuple                    | `tuple([1,2,3]) → (1,2,3)`          | Converts list to immutable tuple                      |\n",
    "| `set()`   | Set                      | `set([1,1,2]) → {1,2}`              | Converts **list to set**, removing duplicate values       |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3c84396",
   "metadata": {},
   "source": [
    "As an example of type **casting**, let's cast an integer to a float."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "3dd8774d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "<class 'int'>\n",
      "1.0\n",
      "<class 'float'>\n"
     ]
    }
   ],
   "source": [
    "num = 1\n",
    "print(num)\n",
    "print(type(num))\n",
    "\n",
    "num = float(num)\n",
    "print(num)\n",
    "print(type(num))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e0f235a",
   "metadata": {},
   "source": [
    "**Type coercion** is performed automatically by the Python interpreter at runtime. The Python interpreter decides the data type."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "41c3a4aa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10.0\n",
      "<class 'float'>\n"
     ]
    }
   ],
   "source": [
    "### type coercion\n",
    "\n",
    "a = 7             # int\n",
    "b = 3.0           # float\n",
    "c = a + b         # Python automatically converts 'a' to a float (7.0) before addition\n",
    "print(c)          # Output: 10.0\n",
    "print(type(c))    # Output: <class 'float'>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20733981",
   "metadata": {},
   "source": [
    "Examples of type casting vs type coercion:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d226e717",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num's type:\t <class 'int'>\n",
      "num's new type:\t <class 'str'>\n",
      "3 + 0.14 is 3.14 and has the type: <class 'float'>\n"
     ]
    }
   ],
   "source": [
    "### type casting\n",
    "num = 5\n",
    "print(\"num's type:\\t\", type(num))\n",
    "print(\"num's new type:\\t\", 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": "code",
   "execution_count": null,
   "id": "1c63079a",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Type Conversion\n",
    "### Print the data type of variable 'num' after the addition\n",
    "### The result should be as the cell below\n",
    "### Your code begins here\n",
    "\n",
    "num = \"100.1\"\n",
    "num = float(num) + 1.0\n",
    "\n",
    "\n",
    "### Your code ends here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6efa5ad3",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'float'>\n"
     ]
    }
   ],
   "source": [
    "print(type(num))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1794b75c",
   "metadata": {},
   "source": [
    "### Type Hinting\n",
    "Type hinting, also called **type annotation**, lets you write the expected type next to a variable name. A type hint is a note for humans and development tools; Python does not enforce it by itself when the program runs.\n",
    "\n",
    "At this point, focus on the basic idea:\n",
    "\n",
    "```python\n",
    "age: int = 20\n",
    "name: str = \"Alice\"\n",
    "height: float = 5.9\n",
    "is_active: bool = True\n",
    "```\n",
    "\n",
    "The annotation after the colon says what kind of value the variable is expected to hold. Later, when we define our own functions, we will use the same notation for function parameters and return values:\n",
    "\n",
    "```python\n",
    "def add(a: int, b: int) -> int:\n",
    "    return a + b\n",
    "```\n",
    "\n",
    "For now, remember two rules:\n",
    "\n",
    "- type hints improve readability and help tools catch mistakes early;\n",
    "- type hints do not convert values or stop the program at runtime.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "071a7a51",
   "metadata": {},
   "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": "ac00bb4f",
   "metadata": {},
   "source": [
    "## Python 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. Modules, on the other hand, need to be imported to use. For the functionalities that Python does not provide, we either\n",
    "\n",
    "1. Find a third-party **package** (module or library) with the functions, install the package, and use the contained functions, or\n",
    "2. Write a **user-defined** custom function. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47e29003",
   "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": "caf4cda6",
   "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": null,
   "id": "e8ac9c01",
   "metadata": {},
   "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": "435d7f0c",
   "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} ../../images/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": "4a5e1218",
   "metadata": {},
   "source": [
    "We may group the 71 built-in functions by their purposes.\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/conversion | **`bool`**, **`int`**, **`float`**, `complex`, **`str`**, `bytes`, `bytearray`, `memoryview`, **`list`**, **`tuple`**, `set`, `frozenset`, **`dict`**, **`range`** | Convert or construct core types.                                 |\n",
    "| Object/attribute introspection  | **`type`**, **`isinstance`**, `issubclass`, **`id`**, `hash`, `dir`, `vars`, `repr`, `ascii`                                                   | `vars(obj)` → `obj.__dict__` when available.                     |\n",
    "| Attribute access                | `getattr`, `setattr`, `delattr`, `hasattr`                                                                                         | Dynamic attribute management.                                    |\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",
    "| I/O                             | **`print`**, **`input`**, `open`                                                                                                           | `open` returns a context manager; prefer `with open(...) as f:`. |\n",
    "| Formatting / representation     | `format`, `bin`, `oct`, `hex`                                                                                                      | Also see f-strings for formatting.                               |\n",
    "| Object model (OOP helpers)      | `object`, `property`, `classmethod`, `staticmethod`, `super`                                                                       | Define descriptors and class behaviors.                          |\n",
    "| Execution / metaprogramming     | `compile`, `eval`, `exec`                                                                                                          | Use with care; security concerns for untrusted input.            |\n",
    "| Environment / namespaces        | `globals`, `locals`                                                                                                                | Introspection of current namespaces.                             |\n",
    "| Help/debugging                  | `help`, `breakpoint`                                                                                                               | `breakpoint()` respects `PYTHONBREAKPOINT`.                      |\n",
    "| Import                          | `__import__`                                                                                                                       | Low-level import; usually use `import` statement instead.        |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce81ad3b",
   "metadata": {},
   "source": [
    "But Python has more than the built-in functions listed above. Let's look at arithmetic/math functions as an example. You see that Python provides three groups of arithmetic **functions**:\n",
    "1. **built-in** functions (the 7 functions as listed in the table above)\n",
    "2. **`operator`** module functions\n",
    "3. **`math`** module functions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "64f51e70",
   "metadata": {},
   "source": [
    "For the **`operator`** module, there are math functions to perform the same operations as the arithmetic operators, which you will need to perform operations such `map` and `reduce`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "643f1238",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import operator\n",
    "operator.add(3, 2)       # 5\n",
    "operator.sub(3, 2)       # 1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1c5fca0d",
   "metadata": {},
   "source": [
    "The `math` module functions do better with high-level arithmetic, as shown below. These functions are self-explanatory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ca5fac69",
   "metadata": {},
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48660645",
   "metadata": {},
   "source": [
    "| Function              | Purpose                 | Example        |    |      |\n",
    "| --------------------- | ----------------------- | ---------------|----|------ |\n",
    "| `math.sqrt(x)`        | Square root             | `math.sqrt(16)` | →  | `4.0`   |\n",
    "| `math.factorial(x)`   | Factorial               | `math.factorial(5)` | → | `120` |\n",
    "| `math.ceil(x)`        | Round up                | `math.ceil(3.2)` | → | `4`      |\n",
    "| `math.floor(x)`       | Round down              | `math.floor(3.9)` | → | `3`     |\n",
    "| `math.prod(iterable)` | Multiply all items      | `math.prod([2, 3, 4])` | → | `24` |\n",
    "| `math.fabs(x)`        | Absolute (always float) | `math.fabs(-7)` | → | `7.0`     |\n",
    "| `math.isfinite(x)`    | Finite number?          | `math.isfinite(2)` | → | `True` |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ab6e2c3",
   "metadata": {},
   "source": [
    "```{index} argument\n",
    "```\n",
    "\n",
    "### Arguments\n",
    "\n",
    "When you call a function, the `expression` in parentheses is called an **argument**. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "32d3b139",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Any number of arguments\n"
     ]
    }
   ],
   "source": [
    "int('101')           ### take one argument\n",
    "math.pow(5, 2)       ### take two\n",
    "int('101', 2)        ### take additional optional arguments, such as base 2 here\n",
    "round(math.pi, 3)    ### takes an optional second argument, **decimal places** \n",
    "print('Any', 'number', 'of', 'arguments')   ### multiple arguments"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "57b81d54",
   "metadata": {},
   "source": [
    "### Return Values\n",
    "\n",
    "When you call built-in functions such as `abs`, `round`, `sqrt`, and `pow`, they return a value you can assign to a variable or use as part of an expression. \n",
    "\n",
    "Some use the `print` function to display values, but they don't return values we assign to variables or use in expressions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50e1de8b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.656366395715726"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import math\n",
    "\n",
    "math.sqrt(42 / math.pi)            ### returns value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9f34c75e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.656366395715726"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "radius = math.sqrt(42 / math.pi)    ### assign to variable\n",
    "radius"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3d640fb",
   "metadata": {},
   "source": [
    "If a function doesn't have a `return` statement, it returns **`None`**, which is a special value like `True` and `False`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74b379e4",
   "metadata": {},
   "source": [
    "You have used the `print` function to display a string, but it does not use a `return` statement to return a value. If we assign the result to a variable, it still displays the string. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "97d6346c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "None\n"
     ]
    }
   ],
   "source": [
    "print(print())   ### returns None"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8261678",
   "metadata": {},
   "source": [
    "## Basic Types"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c47e196",
   "metadata": {},
   "source": [
    "### Numbers\n",
    "\n",
    "Python has three basic number types: integers (e.g., 1), floating-point numbers (e.g., 1.0), and complex numbers. The standard mathematical order of operations is followed for basic arithmetic operations. Note that dividing two integers results in a floating-point number, and dividing by zero will generate an error. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4af3c49d",
   "metadata": {},
   "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": "code",
   "execution_count": null,
   "id": "3ad242e2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 <class 'int'>\n",
      "3 <class 'int'>\n",
      "0.5 <class 'float'>\n",
      "1.0 <class 'float'>\n"
     ]
    }
   ],
   "source": [
    "num1 = 1 + 1\n",
    "num2 = 1 * 3         \n",
    "num3 = 1 / 2\n",
    "num4 = 2 / 2             ### output 1.0, not 1\n",
    "\n",
    "print(num1, type(num1))\n",
    "print(num2, type(num2))\n",
    "print(num3, type(num3))\n",
    "print(num4, type(num4))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5de2f00f",
   "metadata": {},
   "source": [
    "The modulus operation (also known as the mod function) is represented by the percent sign. It returns what remains after the division:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d18ab8b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "print(4 % 2)\n",
    "print(5 % 2)\n",
    "print(9 // 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "08647c99",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: How many hours and minutes are there in 12500 seconds?\n",
    "### Use numeric operators\n",
    "### Your code starts here\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "20564769",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3 hours, 28 minutes, and 20 seconds\n"
     ]
    }
   ],
   "source": [
    "### solution\n",
    "total_seconds = 12500\n",
    "\n",
    "remaining_seconds = total_seconds % 60\n",
    "minutes = total_seconds // 60\n",
    "remaining_minutes = minutes % 60\n",
    "# hours = total_seconds // 3600  # 3600 seconds in an hour\n",
    "hours = minutes // 60  # 60 minutes in an hour\n",
    "\n",
    "print(f\"{hours} hours, {remaining_minutes} minutes, and {remaining_seconds} seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d65db00",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "### Strings\n",
    "\n",
    "Python represents sequences of letters, which are called **strings** because the letters are strung together like beads on a necklace. Strings are one of the most commonly used built-in types. \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.\n",
    "\n",
    "Some features about strings in Python:\n",
    "\n",
    "- A string is a sequence of characters enclosed in quotes.\n",
    "- You can use single, double, or triple quotation marks to create a string; they are all legal.\n",
    "- Double quotes make it easy to write a string that contains an apostrophe, which is treated the same as single quotes in programming."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "759292f6",
   "metadata": {},
   "source": [
    "#### Creating String Variables"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b50fc1e",
   "metadata": {},
   "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)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "416b1674",
   "metadata": {},
   "source": [
    "#### Quotation Marks & Escaping\n",
    "\n",
    "An escape sequence is a combination of a backslash `\\` with a special character/symbol to treat the special characters as regular strings. \n",
    "\n",
    "Observe the following two strings. You see that we are trying to honor the single quote in a pair of double quotes. For that, you can either:\n",
    "\n",
    "- **enclose** the single quotation mark inside the double quotation marks as in the first example, or enclose the double quote with single quotes like the 2nd. \n",
    "- use an **escape sequence**. Note that in s3, we have three single quotation marks, and we are able to produce the same results as the first example.\n",
    "- Starting from s4, we have a syntax error because the quotation marks are not properly closed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "88c76c5d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "It's a sunny day.\n",
      "It\"s a sunny day.\n",
      "It's a sunny day.\n"
     ]
    }
   ],
   "source": [
    "s1 = \"It's a sunny day.\"   ### double quote enclose single\n",
    "s2 = 'It\"s a sunny day.'   ### ... but legal\n",
    "s3 = 'It\\'s a sunny day.'  ### escape single quote\n",
    "print(s1, s2, s3, sep=\"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c731a686",
   "metadata": {},
   "source": [
    "The enclosing quotations have to be symmetrical, otherwise you would have a syntax error."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "561ad1d1-a9a5-4f8f-ab80-53ff0b82e69b",
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "unterminated string literal (detected at line 1) (3841685661.py, line 1)",
     "output_type": "error",
     "traceback": [
      "  \u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[51]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[31m    \u001b[39m\u001b[31ms4 = 'It's a sunny day.'   ### illegal: not closed\u001b[39m\n                           ^\n\u001b[31mSyntaxError\u001b[39m\u001b[31m:\u001b[39m unterminated string literal (detected at line 1)\n"
     ]
    }
   ],
   "source": [
    "%%expect SyntaxError\n",
    "\n",
    "s4 = 'It's a sunny day.'   ### illegal: not closed\n",
    "s5 = \"It\"s a sunny day.\"   ### illegal: not closed\n",
    "print(s4, s5, sep=\"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd504d5f",
   "metadata": {},
   "source": [
    "Commonly used escape sequences are as follows.\n",
    "\n",
    "| Sequence | Meaning                                  |\n",
    "| -------- | ---------------------------------------- |\n",
    "| `\\'`     | Single quote inside single-quoted string |\n",
    "| `\\\"`     | Double quote inside double-quoted string |\n",
    "| `\\\\`     | Backslash literal                        |\n",
    "| `\\n`     | Newline                                  |\n",
    "| `\\t`     | Tab                                      |\n",
    "\n",
    "Some examples of escape sequences are:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "c72504ab",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First line \n",
      " Second line\n",
      "Name:\tDoris\n",
      "He said \"Python is great!\"\n",
      "I'm learning Python\n"
     ]
    }
   ],
   "source": [
    "print(\"First line \\n Second line\")      ### \\n: gives new line (break)\n",
    "print(\"Name:\\tDoris\")                   ### \\t: tab\n",
    "print(\"He said \\\"Python is great!\\\"\")   ### print \" inside \"\"\n",
    "print('I\\'m learning Python')           ### show ' as a character, not quotation mark"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5cfa3dbf",
   "metadata": {},
   "source": [
    "Observe and see if the print output makes sense to you."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "b8c270dd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PS C:\\Users\\tychen>\n"
     ]
    }
   ],
   "source": [
    "print(\"PS C:\\\\Users\\\\tychen>\")          ### \\\\ to show \\"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb9cc652",
   "metadata": {},
   "source": [
    "#### Common string operations\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": "markdown",
   "id": "880b82df",
   "metadata": {},
   "source": [
    "Here we have one example for each of the string operations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "2c13cb11",
   "metadata": {},
   "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": "7e1d151d",
   "metadata": {},
   "source": [
    "**Exercise: String Manipulation**\n",
    "- What will be the output of this code?  \n",
    "- Guess first and then activate Live Coding and run the code in the cell below to find out.\n",
    "\n",
    "```python\n",
    "s = \"hello\"\n",
    "t = s\n",
    "s = s.upper()\n",
    "print(t)\n",
    "```\n",
    "A) HELLO  \n",
    "B) hello  \n",
    "C) Error  \n",
    "D) None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c8f472f0",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Use this code cell to test.\n",
    "\n",
    "\n",
    "\n",
    "###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "ac242ae9",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [],
   "source": [
    "### solution: comment out the print statement \n",
    "#   to see the output of t\n",
    "\n",
    "s = \"hello\"\n",
    "t = s\n",
    "s = s.upper()\n",
    "# print(t)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "253445b9",
   "metadata": {},
   "source": [
    "#### Indexing and Slicing \n",
    "\n",
    "Strings are **sequences** of characters. You can access specific elements using **square bracket notation**. Python indexing starts at zero. Negative indexing in slicing starts with -1 from the end element."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "310534e4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "h\n",
      "o\n",
      "o\n"
     ]
    }
   ],
   "source": [
    "s = 'hello'\n",
    "print(s[0])\n",
    "print(s[4])\n",
    "print(s[-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c16e13d",
   "metadata": {},
   "source": [
    "**Slice notation** allows you to grab parts of a string. Use a **`colon`** to specify the start and stop indices. The **stop index is not included**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b5b24f7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "applebananacherry\n",
      "apple\n",
      "banana\n",
      "cherry\n",
      "\n",
      "cherr\n"
     ]
    }
   ],
   "source": [
    "s = 'applebananacherry'\n",
    "print(s[0:])     ### applebananacherry\n",
    "print(s[:5])     ### apple\n",
    "print(s[5:11])   ### banana\n",
    "print(s[-6:])    ### cherry\n",
    "print(s[-6:0])   ### \n",
    "print(s[-6:-1])  ### cherr (stop exclusive)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "830e97e5",
   "metadata": {},
   "source": [
    "### Boolean Type\n",
    "\n",
    "The type of a Boolean value is `bool`. The only two Boolean values are `True` and `False`. They are built-in keywords and must be capitalized.\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": null,
   "id": "cc9a7c53",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "3 > 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "84371442",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "num1 is not greator 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 greator than num2.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14c573b8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Is student: True\n",
      "Is graduated: False\n"
     ]
    }
   ],
   "source": [
    "is_student = True\n",
    "is_graduated = False\n",
    "\n",
    "print(f\"Is student: {is_student}\")      \n",
    "print(f\"Is graduated: {is_graduated}\")   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a8bf5829",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The person is a student.\n"
     ]
    }
   ],
   "source": [
    "if is_student:                          ### in this case, True\n",
    "    print(\"The person is a student.\")\n",
    "else:\n",
    "    print(\"The person is not a student.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "699e7526",
   "metadata": {},
   "source": [
    "#### Boolean Expressions\n",
    "\n",
    "A **boolean expression** is an expression that is either `True` or `False`.\n",
    "For example, the following expressions use the equals operator, `==`, which compares two values and produces `True` if they are equal and `False` otherwise. Remember that there are six relational/comparison operators: `==` `!=` `>` `<` `>=` `<=`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3f68a702",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True False\n"
     ]
    }
   ],
   "source": [
    "t_f_1 = 5 == 5\n",
    "t_f_2 = 5 == 7\n",
    "print(t_f_1, t_f_2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c85eb11",
   "metadata": {},
   "source": [
    "A common error is to use a **single equal sign** (`=`) instead of a **double equal sign** (`==`).\n",
    "Remember that `=` assigns a value to a variable and `==` compares two values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61547727",
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 5       ### assignment\n",
    "y = 7       ### assignment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "08e36cda",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x == y      ### comparison/relational"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3789222f",
   "metadata": {},
   "source": [
    "`True` and `False` are special values that belong to the type `bool`;\n",
    "they are not strings:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3bff1182",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'bool'>\n",
      "<class 'bool'>\n"
     ]
    }
   ],
   "source": [
    "print(type(True))\n",
    "print(type(False))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03d12fba",
   "metadata": {},
   "source": [
    "The `==` operator is one of the **6 relational operators**; the others are:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e9150d1a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x != y               # x is not equal to y\n",
    "x > y                # x is greater than y\n",
    "x < y                # x is less than y\n",
    "x >= y               # x is greater than or equal to y\n",
    "x <= y               # x is less than or equal to y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "333d5976",
   "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)`;\n",
    "- idiom: `if not items:` checks emptiness."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4330fcdc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "False\n",
      "True\n",
      "True\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(None, None)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Minimal truthy/falsy examples\n",
    "print(bool(0)), print(bool(''))        # False\n",
    "print(bool('0')), print(bool([0]))     # True"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "240f4b13",
   "metadata": {},
   "source": [
    "## Collection Types\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",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da204028",
   "metadata": {},
   "source": [
    "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 look 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": "3227525f",
   "metadata": {},
   "source": [
    "### Mutability\n",
    "\n",
    "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": "62dfd965",
   "metadata": {},
   "source": [
    "### Lists (Ordered Collections)\n",
    "\n",
    "Lists store **multiple** items in **order** and are **mutable** (can be changed):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "eea52390",
   "metadata": {},
   "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": "52ee45c0",
   "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`\n",
    "5. Update: `numbers[0] = 99` → `[99, 2, 3, 4, 5, 6]`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "89fd3adf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Original list: ['apple', 'banana', 'cherry']\n",
      "After append: ['apple', 'banana', 'cherry', 'date']\n",
      "First fruit: apple\n",
      "Number of fruits: 4\n"
     ]
    }
   ],
   "source": [
    "fruits = [\"apple\", \"banana\", \"cherry\"]        ### create a list by assignment\n",
    "print(f\"\\nOriginal list: {fruits}\")\n",
    "\n",
    "fruits.append(\"date\")                         ### mutable: update/change the list\n",
    "print(f\"After append: {fruits}\")\n",
    "\n",
    "print(f\"First fruit: {fruits[0]}\")            ### indexing\n",
    "print(f\"Number of fruits: {len(fruits)}\")     ### length"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "26935c03",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "After modification: ['apple', 'banana', 'cranberry', 'date']\n"
     ]
    }
   ],
   "source": [
    "fruits[2] = \"cranberry\"                     ### lists are mutable: modify an element\n",
    "print(f\"After modification: {fruits}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9acd512",
   "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": "56188e72",
   "metadata": {},
   "source": [
    "rgb_color = (255, 128, 0)\n",
    "single = (42,)             # Note the comma for single-item tuple"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "e839f7cb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Converted to tuple: ('apple', 'banana', 'cranberry', 'date')\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": "b38bfae4",
   "metadata": {},
   "source": [
    "Since tuples are immutable, the following operation would generate an error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "83fbefd2",
   "metadata": {},
   "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": "ac1100c8",
   "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": 32,
   "id": "95f0aadb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'name': 'Alice', 'age': 20, 'major': 'IST'}"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "student = {\n",
    "    \"name\": \"Alice\",\n",
    "    \"age\": 20,\n",
    "    \"major\": \"IST\"\n",
    "}\n",
    "student"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32c6ea00",
   "metadata": {},
   "source": [
    "Common dictionary operations:\n",
    "- **Access**: `student[\"name\"]` → `\"Alice\"`\n",
    "- Add/Update: `student[\"gpa\"] = 3.8`\n",
    "- **Keys**: `student.keys()` → `dict_keys(['name', 'age', 'major'])`\n",
    "- **Values**: `student.values()` → `dict_values(['Alice', 20, 'Computer Science'])`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "b3a8424d",
   "metadata": {},
   "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": "1aa30c31",
   "metadata": {},
   "source": [
    "### Sets\n",
    "\n",
    "A **set** is an unordered collection of unique elements. Sets are useful for removing duplicates and performing mathematical set operations.\n",
    "\n",
    "Key characteristics:\n",
    "- **Unordered**: Elements have no defined order\n",
    "- **Unique**: Automatically removes duplicate values\n",
    "- **Mutable**: Can add/remove elements\n",
    "- **No indexing**: Cannot access elements by position"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "cea15073",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Set: {1, 2, 3, 4, 5}\n",
      "Unique values: {8, 9, 2, 5}\n",
      "From list: {24.1, 25.0, 23.5}\n"
     ]
    }
   ],
   "source": [
    "# Creating sets\n",
    "unique_numbers = {1, 2, 3, 4, 5}\n",
    "print(f\"Set: {unique_numbers}\")\n",
    "\n",
    "# Duplicates are automatically removed\n",
    "data = {5, 2, 8, 2, 5, 9}\n",
    "print(f\"Unique values: {data}\")\n",
    "\n",
    "# Creating from a list\n",
    "measurements = [23.5, 24.1, 23.5, 25.0]\n",
    "unique = set(measurements)\n",
    "print(f\"From list: {unique}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "5291d953",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Union: {1, 2, 3, 4, 5}\n",
      "Intersection: {3}\n",
      "Difference: {1, 2}\n"
     ]
    }
   ],
   "source": [
    "# Basic set operations\n",
    "set_a = {1, 2, 3}\n",
    "set_b = {3, 4, 5}\n",
    "\n",
    "print(f\"Union: {set_a | set_b}\")          # All elements\n",
    "print(f\"Intersection: {set_a & set_b}\")   # Common elements\n",
    "print(f\"Difference: {set_a - set_b}\")     # In A but not B"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": ".venv",
   "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.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
