{
 "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"
   ]
  }
 ],
 "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
}
