{
    "cells": [
        {
            "cell_type": "markdown",
            "id": "a14edb7e",
            "metadata": {
                "editable": true,
                "slideshow": {
                    "slide_type": ""
                },
                "tags": []
            },
            "source": [
                "# Python Basic Syntax"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 1,
            "id": "cbefe58a-9ea2-44f3-8987-5d095422f9a0",
            "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\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"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "633d687b-d447-4305-b6d3-01de9cd7e71d",
            "metadata": {},
            "source": [
                "```{figure} ../../images/python-syntax.webp\n",
                "---\n",
                "name: python-syntax-overview\n",
                "width: 70%\n",
                "---\n",
                "[Python Syntax Overview](https://data-flair.training/blogs/python-syntax-semantics/){cite:ps}`TechVida_2017`\n",
                "```"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "2981b69c",
            "metadata": {},
            "source": [
                "## Indentation and Block Structure"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "cb4a048d",
            "metadata": {},
            "source": [
                "In Python, **indentation** defines **code blocks** instead of braces (`{}`), which many other languages use. Any line ending with a colon (`:`), such as `if`, `for`, `while`, `def`, or `class`, starts a new block, and the indented lines that follow belong to that block. Python expects consistent indentation (commonly `4` spaces per level), and mixing tabs and spaces or misaligning lines can raise `IndentationError`. When indentation changes, Python treats that as entering or leaving a block, so correct spacing controls program structure and execution flow."
            ]
        },
        {
            "cell_type": "markdown",
            "id": "13fa1498",
            "metadata": {},
            "source": [
                "```text\n",
                "for i in range(5):\n",
                "print(i)                ### This line is not indented, so it will cause an error\n",
                "```\n",
                "\n",
                "Output    \n",
                "```text\n",
                "Cell In[2], line 2\n",
                "    print(i)                ### This line is not indented, so it will cause an error\n",
                "    ^\n",
                "IndentationError: expected an indented block after 'for' statement on line 1\n",
                "```"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 2,
            "id": "a7b0a4c8",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "0\n",
                        "1\n",
                        "2\n",
                        "3\n",
                        "4\n"
                    ]
                }
            ],
            "source": [
                "for i in range(5):\n",
                "    print(i)            ### This line is indented, so it will work correctly"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "d9c50c2c",
            "metadata": {},
            "source": [
                "## Statement Formatting"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "6e4c35cf",
            "metadata": {},
            "source": [
                "In Python, a statement usually ends at a newline, so each line is typically one statement. You can place multiple simple statements on one line using semicolons (`;`), but this is generally **discouraged** because it reduces readability. For long statements, Python allows implicit line continuation inside parentheses `()`, brackets `[]`, or braces `{}`, which is the preferred way to split expressions across lines. Explicit continuation with a backslash (`\\`) also works, but it is fragile because a trailing space after the backslash will cause an error. In practice, write one statement per line and use **parentheses** for **multi-line expressions**."
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 3,
            "id": "22994888",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "30\n"
                    ]
                }
            ],
            "source": [
                "### 1) Newlines: one statement per line (preferred)\n",
                "x = 10\n",
                "y = 20\n",
                "total = x + y\n",
                "print(total)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 4,
            "id": "e91c2739",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "30\n"
                    ]
                }
            ],
            "source": [
                "### 2) Semicolons: multiple statements on one line (valid, but less readable)\n",
                "x = 10; y = 20; print(x + y)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 5,
            "id": "f1617a2c",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "600\n"
                    ]
                }
            ],
            "source": [
                "### 3) Multi-line with parentheses (preferred)\n",
                "total = (\n",
                "    100\n",
                "    + 200\n",
                "    + 300\n",
                ")\n",
                "print(total)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 6,
            "id": "2691c294",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "600\n"
                    ]
                }
            ],
            "source": [
                "### 4) Multi-line with backslash (works, but less preferred)\n",
                "total = 100 + 200 + \\\n",
                "        300\n",
                "print(total)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 7,
            "id": "3af84925",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Name: Alice Age: 25\n"
                    ]
                }
            ],
            "source": [
                "### 5) Multi-line function call with parentheses\n",
                "print(\n",
                "    \"Name:\", \"Alice\",\n",
                "    \"Age:\", 25\n",
                ")"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "143a1c10",
            "metadata": {},
            "source": [
                "## Input and Output"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "a427552a",
            "metadata": {
                "vscode": {
                    "languageId": "markdown"
                }
            },
            "source": [
                "### `print()` and F-Strings\n",
                "\n",
                "In Python, the **`print()`** function displays output on the screen. It is one of the most commonly used functions for debugging, showing results, and interacting with users.\n",
                "\n",
                "The `print()` function displays values to the console/command line:\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 8,
            "id": "0944cf1c",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "hello, world!\n"
                    ]
                }
            ],
            "source": [
                "print(\"hello, world!\")           ### print a string"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "5cf5eb65-c9a0-45be-a38f-49916fb24558",
            "metadata": {},
            "source": [
                "To print multiple values in one statement, you either **comma-separate** your values or **concatenate** the strings. "
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 9,
            "id": "26645ab0-7453-4c86-9bb5-d5799e6e3bb7",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Name: Alice Age: 25\n",
                        "Name: Alice Age: 25\n"
                    ]
                }
            ],
            "source": [
                "print(\"Name:\", \"Alice\", \"Age:\", 25)       ### commas-separated\n",
                "print(\"Name:\" + \" Alice\" + \" Age:\", 25)   ### + concatenated"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 10,
            "id": "d1aee52c",
            "metadata": {},
            "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 str (not \"int\") to str"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "5ff6ed2f",
            "metadata": {},
            "source": [
                "#### F-Strings \n",
                "\n",
                "**F-strings** (formatted string literals) are a readable and efficient way to format strings in Python (available since Python 3.6). An f-string is often preferred because it is concise and allows **expressions** inside `{}`, so you do not need to manually convert values to strings:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 11,
            "id": "2b91bc92",
            "metadata": {},
            "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": [
                "#### Print Function Parameters\n",
                "\n",
                "The `print()` function has optional parameters: \n",
                "- `object(s)`: one or more values to print. All are converted to strings before printing.\n",
                "- `sep`: the string placed between objects; the default is a space.\n",
                "- `end`: the string added at the end of the output; the default is a newline (`\"\\n\"`).\n",
                "- `file`: the output destination; the default is `sys.stdout`.\n",
                "- `flush`: if `True`, forces immediate output; the default is `False`."
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 12,
            "id": "6ddc5db8",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "A B C (separator is space by default)\n",
                        "A-B-C\n",
                        "0\n",
                        "1\n",
                        "2\n",
                        "3\n",
                        "4\n",
                        "0 1 2 3 4 "
                    ]
                }
            ],
            "source": [
                "### sep\n",
                "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",
                "\n",
                "### end\n",
                "# list 1: print with different end characters\n",
                "for num in range(5):\n",
                "    print(num)                  ### Print numbers on separate lines\n",
                "# list 2: print with different end characters\n",
                "for num in range(5):\n",
                "    print(num, end=\" \")         ### Print numbers on the same line separated by space"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 13,
            "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 begins here\n",
                "\n",
                "\n",
                "### Your code ends here"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 14,
            "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": [
                "print(\"hello, world\")"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "d0d49480-2e7f-4828-b277-78ad9a6353e5",
            "metadata": {},
            "source": [
                "### Keyboard Input\n",
                "\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": "a7b378bc",
            "metadata": {},
            "source": [
                "```python\n",
                "name = input(\"Enter your name: \")\n",
                "print(\"Hello, \" + name + \"!\")\n",
                "```\n",
                "Output:\n",
                "\n",
                "```text\n",
                "Enter your name: Alice\n",
                "Hello, Alice!\n",
                "```"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "bd9894c4",
            "metadata": {},
            "source": [
                "- Type Conversion with Input\n",
                "\n",
                "```python\n",
                "age = input(\"Enter your age: \")   \n",
                "\n",
                "print(type(age))                      ### age is of string type\n",
                "\n",
                "age = int(age)                        ### convert input string to integer\n",
                "\n",
                "print(type(age))\n",
                "print(f\"You are {age} years old.\")\n",
                "```\n",
                "\n",
                "Output:\n",
                "\n",
                "```text\n",
                "Enter your age: 35\n",
                "<class 'str'>\n",
                "<class 'int'>\n",
                "You are 35 years old.\n",
                "```"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "4eaf4149",
            "metadata": {},
            "source": [
                "- Type Conversion: Early\n",
                "\n",
                "```python\n",
                "age = int(input(\"Enter your age: \"))      ### Directly convert input to integer\n",
                "\n",
                "print(type(age))\n",
                "\n",
                "print(f\"You are {age} years old.\")\n",
                "```\n",
                "\n",
                "Output:\n",
                "```text\n",
                "Enter your age: 35\n",
                "<class 'int'>\n",
                "You are 35 years old.\n",
                "```"
            ]
        },
        {
            "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",
                "\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.\n",
                "4. <span style=\"color: darkred\">**Disable code temporarily**</span>: 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": 19,
            "id": "a9a51b86",
            "metadata": {},
            "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": "markdown",
            "id": "d56e671d",
            "metadata": {},
            "source": [
                "### Docstring\n",
                "\n",
                "Unlike comments, which are ignored by the Python interpreter at runtime, docstrings are string literals used for documentation. They are processed by the interpreter and can be accessed with `__doc__` or `help()` as part of the program.\n",
                "\n",
                "Usually, a **docstring** is a string literal written as the first statement inside a module, function, class, or method to describe what it does, its inputs, outputs, or behavior. By convention it uses triple quotes (`\"\"\"...\"\"\"`) so it can span multiple lines. "
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 20,
            "id": "a612cb9b",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "28.274333882308138\n",
                        "Return the area of a circle given its radius.\n"
                    ]
                }
            ],
            "source": [
                "def area_circle(radius):\n",
                "    \"\"\"Return the area of a circle given its radius.\"\"\"\n",
                "    import math\n",
                "    return math.pi * radius**2\n",
                "\n",
                "print(area_circle(3))      # 28.274333882308138\n",
                "print(area_circle.__doc__) # Return the area of a circle given its radius.\n"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "272668d5-5ede-4d0a-8cec-71134ad1c8af",
            "metadata": {},
            "source": [
                "## Object\n",
                "\n",
                "In Python, everything is an **object**, and every object has: \n",
                "- **identity** (unique ID) (`id()`)\n",
                "- **value**\n",
                "- **type** (`type()`)"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "cde537c0",
            "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. Notice that these objects have different IDs."
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 21,
            "id": "7b2f8bae",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "4389741856\n",
                        "4507684368\n",
                        "4501683200\n",
                        "4615658240\n"
                    ]
                }
            ],
            "source": [
                "num1 = 42\n",
                "num2 = 3.14\n",
                "greeting = \"hello\"\n",
                "fruits = [\"apple\", \"banana\", \"cherry\"]\n",
                "\n",
                "print(id(num1))\n",
                "print(id(num2))\n",
                "print(id(greeting))\n",
                "print(id(fruits))"
            ]
        },
        {
            "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 (such as variable names). \n",
                "\n",
                "For example, if you try to assign a string to a variable named _class_, you will receive a syntax error because `class` is a **keyword**."
            ]
        },
        {
            "cell_type": "markdown",
            "id": "8e138da2-36bb-4b48-9cb0-e4b2dac94549",
            "metadata": {
                "language": "markdown"
            },
            "source": [
                "```text\n",
                "class = 'Assigning a string to a keyword to be a variable name...'\n",
                "```\n",
                "\n",
                "Running this raises `SyntaxError` because `class` is a reserved keyword in Python."
            ]
        },
        {
            "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 are part of Python's syntax. Instead of memorizing all 35 at once, it helps to group some common ones by the jobs they do:\n",
                "\n",
                "| Category | Examples |\n",
                "|---|---|\n",
                "| Flow control | `if`, `elif`, `else`, `for`, `while`, `break`, `continue`, `pass` |\n",
                "| Definitions | `def`, `class`, `lambda` |\n",
                "| Boolean logic and identity | `and`, `or`, `not`, `is`, `in`, `True`, `False`, `None` |\n",
                "| Imports and scope | `import`, `from`, `global`, `nonlocal` |\n",
                "| Exceptions and context | `try`, `except`, `finally`, `raise`, `assert`, `with`, `as` |\n",
                "| Async and generators | `async`, `await`, `yield` |\n",
                "\n",
                "In most development environments, keywords are displayed in a different color; if you try to use one as a variable name, the editor or interpreter will warn you."
            ]
        },
        {
            "cell_type": "markdown",
            "id": "b9a70e08",
            "metadata": {},
            "source": [
                "To show all the Python keywords, you can do:"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "d42f94c5",
            "metadata": {},
            "source": [
                "```python\n",
                "from keyword import kwlist\n",
                "print(\"Number of Python keywords:\", len(kwlist))\n",
                "print(\"All Python keywords:\", kwlist)\n",
                "```\n",
                "The output would look like:\n",
                "```python\n",
                "Number of Python keywords: 35\n",
                "All Python keywords: ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']\n",
                "```"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "d0118475",
            "metadata": {},
            "source": [
                "As stated earlier, keywords form the **program structure**. The examples below show how keywords act like the grammatical parts of a program.\n",
                "\n",
                "For example, `if` is a keyword in Python and is highlighted in most code editors.\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 24,
            "id": "ff996be3",
            "metadata": {},
            "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": "markdown",
            "id": "e33caaf9",
            "metadata": {},
            "source": [
                "And `for` and `in` are also keywords."
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 25,
            "id": "a738778c",
            "metadata": {},
            "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 in specific contexts, but can be used as regular identifiers (such as variable or function names) in other contexts. As of Python 3.12, there are four [soft keywords](https://docs.python.org/3.13/reference/lexical_analysis.html#soft-keywords): **match**, **case**, **_**, and **type**."
            ]
        },
        {
            "cell_type": "markdown",
            "id": "c5a1124b-57e2-49ee-81cf-7c18da972ec1",
            "metadata": {},
            "source": [
                "## Modules and Packages\n",
                "\n",
                "In Python, functions, classes, modules, packages, and libraries are essential tools for organizing and reusing code:\n",
                "\n",
                "| Term | What It Is | Typical Use |\n",
                "|---|---|---|\n",
                "| Function | A named, reusable block of code that performs one specific task and can be called multiple times. | Break problems into smaller steps and avoid repeating logic. |\n",
                "| Class | A blueprint for creating objects that bundle data (attributes) and behavior (methods). | Model real-world entities and organize related state + behavior. |\n",
                "| Module | A single Python file (`.py`) containing code such as functions, classes, and variables. | Split code into files and import what you need. |\n",
                "| Package | A directory of related modules (and often subpackages) that forms a larger namespace. | Organize multi-file projects into clear components. |\n",
                "| Library | A broader collection of packages/modules built to solve common domains or tasks. | Reuse mature tools (e.g., data analysis, web, scientific computing) instead of building from scratch. |\n",
                "\n",
                "Together, these components help make Python code more organized, efficient, and maintainable. The most important distinction for now is:\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": "e733b3b7",
            "metadata": {},
            "source": [
                "### Importing Modules"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "6c9a5a08-a1c6-445d-85a3-45334cae58c9",
            "metadata": {},
            "source": [
                "Python ships with about 300 built-in and standard-library modules. For those modules, you can import them directly and use them (for example, `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",
                "| Aliased import           | `import math as m`    | `m.pi`               | Alias for brevity (common with large libs)  |\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 |"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "3821d11c",
            "metadata": {},
            "source": [
                "**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"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "40bd4944-4391-486e-aa72-7034ed292a83",
            "metadata": {},
            "source": [
                "To use methods or attributes from a module, use the **dot operator** (`.`) between the module name and the attribute name. For example, the Python `math` module provides a variable called `pi` that contains the mathematical constant denoted $\\pi$. We can access it as `math.pi`:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 26,
            "id": "c7f6c1f3-fc38-40eb-a709-6ed0e5e05426",
            "metadata": {},
            "outputs": [
                {
                    "data": {
                        "text/plain": [
                            "5.0"
                        ]
                    },
                    "execution_count": 26,
                    "metadata": {},
                    "output_type": "execute_result"
                }
            ],
            "source": [
                "import math\n",
                "math.sqrt(25)     ### dot operator"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "e1208a0a-c571-4d4b-9fdc-64aadce486ef",
            "metadata": {},
            "source": [
                "### Installing Packages\n",
                "\n",
                "External, third-party modules are created by the Python community. You must use `pip` to install them first (for example, notebook, NumPy, or pandas), then import them before using them. Most software on the Python Package Index (PyPI; https://pypi.org, where `pip` finds 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 install the package into the active kernel:\n",
                "\n",
                "`%pip install [package_name]` "
            ]
        },
        {
            "cell_type": "markdown",
            "id": "ac740e54-5362-4127-9971-6307d3516a4e",
            "metadata": {},
            "source": [
                "For example, NumPy (numeric Python) is a popular package for data science. From inside Jupyter Notebook, you can install it with:"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": 27,
            "id": "e4acd236-f2c2-4456-b107-97889508eb22",
            "metadata": {},
            "outputs": [
                {
                    "name": "stdout",
                    "output_type": "stream",
                    "text": [
                        "Requirement already satisfied: numpy in /Users/tychen/workspace/py/.venv/lib/python3.13/site-packages (2.3.4)\n",
                        "\n",
                        "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m25.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.0.1\u001b[0m\n",
                        "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
                        "Note: you may need to restart the kernel to use updated packages.\n"
                    ]
                }
            ],
            "source": [
                "%pip install numpy"
            ]
        },
        {
            "cell_type": "markdown",
            "id": "d688a290",
            "metadata": {},
            "source": [
                "You probably want to comment the `%pip install` line out after installation as you only need to install it once in the virtual environment. "
            ]
        },
        {
            "cell_type": "markdown",
            "id": "679af114",
            "metadata": {},
            "source": []
        }
    ],
    "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
}
