{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a14edb7e",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "# Python Operators"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "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\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aaa27e65-54d4-4680-bd83-cf2d5ce7797b",
   "metadata": {},
   "source": [
    "## Operators\n",
    "\n",
    "In programming languages, operators are special symbols that perform computations or logical comparisons between values. They form the backbone of most **expressions** — whether you’re performing arithmetic, comparing data, assigning values, or testing relationships between objects. (For a detailed discussion of Expressions and Operators, see [Python Reference/Expressions](https://docs.python.org/3/reference/expressions.html#))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "350327b4",
   "metadata": {},
   "source": [
    "The table below summarizes all Python operators.\n",
    "\n",
    "| Category | Operators | Description | Example |\n",
    "|----------|-----------|-------------|---------|\n",
    "| **Assignment** | `=` `+=` `-=` `*=` `/=` `//=` `%=` `**=` | Assign and update values | `x = 5`, `x += 3` |\n",
    "| **Arithmetic** | `+` `-` `*` `/` `//` `%` `**` | Mathematical operations | `5 + 3`, `5 // 2`, `2 ** 3` |\n",
    "| **Comparison** | `==` `!=` `>` `<` `>=` `<=` | Compare values, return bool | `5 > 3`, `x == y` |\n",
    "| Logical | `and` `or` `not` | Boolean logic | `True and False`, `not True` |\n",
    "| Identity | `is` `is not` | Test object identity | `x is None`, `a is not b` |\n",
    "| **Membership** | `in` `not in` | Test membership in sequence | `'a' in 'cat'`, `5 not in [1,2,3]` |\n",
    "| **Bitwise** | `&` `\\|` `^` `~` `<<` `>>` | Bit-level operations | `5 & 3`, `5 << 1` |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "994950f9",
   "metadata": {},
   "source": [
    "A more detailed overview of all the operators in Python:\n",
    "\n",
    "| No. | Type | Operator | Meaning | Example | Result |\n",
    "| --- | ---- | -------- | ------- | ------- | ------ |\n",
    "| 1 | **Assignment** | `=` | Assign | `x = 5` | `x` is `5` |\n",
    "|  | | `+=` | Add and assign | `x += 3` | `x = x + 3` |\n",
    "|  | | `-=` | Subtract and assign | `x -= 3` | `x = x - 3` |\n",
    "|  | | `*=` | Multiply and assign | `x *= 3` | `x = x * 3` |\n",
    "|  | | `/=` | Divide and assign | `x /= 3` | `x = x / 3` |\n",
    "|  | | `//=` | Floor divide and assign | `x //= 3` | `x = x // 3` |\n",
    "|  | | `%=` | Modulus and assign | `x %= 3` | `x = x % 3` |\n",
    "|  | | `**=` | Exponent and assign | `x **= 3` | `x = x ** 3` |\n",
    "|  | | `:=` | Assignment expression (walrus operator) | `total := sum(data)` | assign sum(data) to total |\n",
    "| 2 |  **Arithmetic** | `+` | Addition | `5 + 3` | `8` |\n",
    "|  | | `-` | Subtraction | `5 - 3` | `2` |\n",
    "|  | | `*` | Multiplication | `5 * 3` | `15` |\n",
    "|  | | `/` | Division | `5 / 2` | `2.5` |\n",
    "|  | | `//` | Floor Division | `5 // 2` | `2` |\n",
    "|  | | `%` | Modulo | `5 % 2` | `1` |\n",
    "|  | | `**` | Exponentiation | `5 ** 2` | `25` |\n",
    "| 3 | **Comparison** | `==` | Equal to | `5 == 5` | `True` |\n",
    "|  | | `!=` | Not equal to | `5 != 3` | `True` |\n",
    "|  | | `>` | Greater than | `5 > 3` | `True` |\n",
    "|  | | `<` | Less than | `5 < 3` | `False` |\n",
    "|  | | `>=` | Greater than or equal | `5 >= 5` | `True` |\n",
    "|  | | `<=` | Less than or equal | `5 <= 3` | `False` |\n",
    "|  | Membership | `in` | Member of | `'a' in 'cat'` | `True` |\n",
    "|  | | `not in` | Not member of | `'x' not in 'cat'` | `True` |\n",
    "|  | Identity | `is` | Same object | `x is y` | Varies |\n",
    "|  | | `is not` | Different object | `x is not y` | Varies |\n",
    "| 4 | **Logical** | `and` | Logical AND | `True and False` | `False` |\n",
    "|  | | `or` | Logical OR | `True or False` | `True` |\n",
    "|  | | `not` | Logical NOT | `not True` | `False` |\n",
    "| 5 | **Bitwise** | `&` | Bitwise AND | `5 & 3` | `1` |\n",
    "|  | | `\\|` | Bitwise OR | `5 \\| 3` | `7` |\n",
    "|  | | `^` | Bitwise XOR | `5 ^ 3` | `6` |\n",
    "|  | | `~` | Bitwise NOT | `~5` | `-6` |\n",
    "|  | | `<<` | Left shift | `5 << 1` | `10` |\n",
    "|  | | `>>` | Right shift | `5 >> 1` | `2` |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4af250b6",
   "metadata": {},
   "source": [
    "## Assignment Operators\n",
    "\n",
    "Assignment operators are used to assign or update the value of a variable. The basic assignment operator is `=`, which stores a value in a variable. Python also provides **augmented assignment operators** that combine an arithmetic operation with assignment, making code more concise.\n",
    "\n",
    "| Operator | Meaning                  | Example    | Equivalent to  |\n",
    "|----------|--------------------------|------------|----------------|\n",
    "| `=`      | Assign                   | `x = 5`    | —              |\n",
    "| `+=`     | Add and assign           | `x += 3`   | `x = x + 3`    |\n",
    "| `-=`     | Subtract and assign      | `x -= 3`   | `x = x - 3`    |\n",
    "| `*=`     | Multiply and assign      | `x *= 3`   | `x = x * 3`    |\n",
    "| `/=`     | Divide and assign        | `x /= 3`   | `x = x / 3`    |\n",
    "| `//=`    | Floor divide and assign  | `x //= 3`  | `x = x // 3`   |\n",
    "| `%=`     | Modulus and assign       | `x %= 3`   | `x = x % 3`    |\n",
    "| `**=`    | Exponent and assign      | `x **= 3`  | `x = x ** 3`   |\n",
    "| `:=`     | Walrus (assign in expr)  | `(n := 10)` | assigns and returns value |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "1e7739af",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10\n",
      "13\n",
      "11\n",
      "44\n",
      "14\n",
      "4\n",
      "16\n",
      "List is long: 5 elements\n"
     ]
    }
   ],
   "source": [
    "x = 10          # basic assignment\n",
    "print(x)\n",
    "\n",
    "x += 3          # x = x + 3\n",
    "print(x)        # 13\n",
    "\n",
    "x -= 2          # x = x - 2\n",
    "print(x)        # 11\n",
    "\n",
    "x *= 4          # x = x * 4\n",
    "print(x)        # 44\n",
    "\n",
    "x //= 3         # x = x // 3\n",
    "print(x)        # 14\n",
    "\n",
    "x %= 5          # x = x % 5\n",
    "print(x)        # 4\n",
    "\n",
    "x **= 2         # x = x ** 2\n",
    "print(x)        # 16\n",
    "\n",
    "# Walrus operator := assigns and returns in one step\n",
    "numbers = [1, 2, 3, 4, 5]\n",
    "if (n := len(numbers)) > 3:\n",
    "    print(f\"List is long: {n} elements\")  # List is long: 5 elements"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84da822b-f37a-402e-8050-ff7e5f12e76f",
   "metadata": {},
   "source": [
    "## Arithmetic Operators\n",
    "\n",
    "An arithmetic operator is a symbol that represents an arithmetic computation. For example:\n",
    "\n",
    "1. The plus sign, `+`, performs addition.\n",
    "2. The minus sign, `-`, is the operator that performs subtraction. \n",
    "3. The asterisk, `*`,  performs multiplication. \n",
    "4. The forward slash, `/`, performs division. Note that in modern Python (Python 3+), the division operator `/` always returns a floating-point number, even if the result is a whole number.\n",
    "5. The integer/floor division operator, `//`, is called **floor division** because it always rounds down (toward the \"floor\").\n",
    "6. The **modulus operator** `%` returns the remainder after division.\n",
    "7. The operator `**` performs exponentiation; that is, it raises a\n",
    "number to a power. In other languages, such as R, MATLAB, Julia, and Excel, the caret `^` is used for exponentiation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "bc531b4b-0c65-4319-b187-3ec088d443e5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "13\n",
      "7\n",
      "30\n",
      "3.3333333333333335\n",
      "3\n",
      "1\n",
      "1000\n"
     ]
    }
   ],
   "source": [
    "a = 10 + 3\n",
    "b = 10 - 3\n",
    "c = 10 * 3\n",
    "d = 10 / 3\n",
    "e = 10 // 3\n",
    "f = 10 % 3\n",
    "g = 10 ** 3\n",
    "\n",
    "print(a, b, c, d, e, f, g, sep=\"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7757017-657b-44ab-9a35-f6b476c3b735",
   "metadata": {},
   "source": [
    "### Integer division and modulus\n",
    "\n",
    "Recall that the **integer division operator**, `//`, divides two numbers and rounds down to an integer. For example, suppose the run time of a movie is 105 minutes. You might want to know how long that is in hours. \n",
    "\n",
    "Conventional division returns a floating-point number:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "f337105e-7ae0-4b08-9f39-a63fb9b3ed56",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.75"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "minutes = 105\n",
    "minutes / 60"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76b74963-573a-4b97-b5c2-1cae12393479",
   "metadata": {},
   "source": [
    "But we don't normally write hours with decimal points.\n",
    "Integer division returns the integer number of hours, rounding down:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "0df250e1-fbfc-4ced-b598-5c1c62dd74e3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "minutes = 105\n",
    "hours = minutes // 60\n",
    "hours"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88f938dd-6ce4-47dc-ac18-a23c4b3d4416",
   "metadata": {},
   "source": [
    "To get the remainder, you could subtract off one hour in minutes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "f4cba0a9-c6cd-47e4-9b0c-02f750e4266d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "45"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "remainder = minutes - hours * 60\n",
    "remainder"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dac22f24-4a99-4f19-97ed-9e441737fbed",
   "metadata": {},
   "source": [
    "Or you could use the **modulus operator**, `%`, which divides two numbers and returns the remainder."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "c9ce77ef-d3ec-4784-a2f4-5e30a4f1c29c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "45"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "remainder = minutes % 60\n",
    "remainder"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47957d5d-ec0f-439b-8474-201bf596551c",
   "metadata": {},
   "source": [
    "The modulus operator is more useful than it might seem.\n",
    "For example, it can check whether one number is divisible by another -- if `x % y` is zero, then `x` is divisible by `y`.\n",
    "\n",
    "Also, it can extract the right-most digit or digits from a number.\n",
    "For example, `x % 10` yields the right-most digit of `x` (in base 10).\n",
    "Similarly, `x % 100` yields the last two digits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "bd256b42-07f7-4065-bba3-70383ad71f69",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 123\n",
    "x % 10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "770d441a-3ce1-4b0b-ba0d-68714dd5c646",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "23"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x % 100"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6209eb64-e27d-4c32-ba3a-2ec4c286c07c",
   "metadata": {},
   "source": [
    "Finally, the modulus operator can do \"clock arithmetic\".\n",
    "For example, if an event starts at 11 AM and lasts three hours, we can use the modulus operator to figure out what time it ends."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "c969c037-674b-4752-ad89-2acbe6c901fd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "start = 11\n",
    "duration = 3\n",
    "end = (start + duration) % 12\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae884158",
   "metadata": {},
   "source": [
    "The event would end at 2 PM."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3c06476",
   "metadata": {},
   "source": [
    "## Comparison Operators"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b1de185",
   "metadata": {},
   "source": [
    "Comparison operators are used to compare values in Python. They allow you to check relationships between variables, such as equality, inequality, and ordering. These operators return a Boolean value (`True` or `False`) based on the result of the comparison. Understanding comparison operators is essential for writing conditional statements and controlling program flow."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1f58302f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "True\n",
      "True\n",
      "False\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "x = 5\n",
    "y = 10\n",
    "\n",
    "print(x == y)   # False, checks equality\n",
    "print(x != y)   # True, checks inequality\n",
    "print(x < y)    # True, less than\n",
    "print(x > y)    # False, greater than\n",
    "print(x <= y)   # True, less than or equal to\n",
    "print(x >= y)   # False, greater than or equal to"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb5fde74",
   "metadata": {},
   "source": [
    "## Logical operators"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "406325eb",
   "metadata": {},
   "source": [
    "**Logical operators** (also called **Boolean operators**) combine or negate boolean expressions and return a `True` or `False` result. Python provides three logical operators:\n",
    "\n",
    "| Operator | Type   | Description                                      | Example              | Result  |\n",
    "|----------|--------|--------------------------------------------------|----------------------|---------|\n",
    "| `and`    | Binary | `True` only if **both** operands are `True`      | `True and False`     | `False` |\n",
    "| `or`     | Binary | `True` if **at least one** operand is `True`     | `True or False`      | `True`  |\n",
    "| `not`    | Unary  | Inverts the boolean value                        | `not True`           | `False` |\n",
    "\n",
    "**Truth table**:\n",
    "\n",
    "| `a`     | `b`     | `a and b` | `a or b` | `not a` |\n",
    "|---------|---------|-----------|----------|---------|\n",
    "| `True`  | `True`  | `True`    | `True`   | `False` |\n",
    "| `True`  | `False` | `False`   | `True`   | `False` |\n",
    "| `False` | `True`  | `False`   | `True`   | `True`  |\n",
    "| `False` | `False` | `False`   | `False`  | `True`  |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d576dda4",
   "metadata": {},
   "source": [
    "The `and` operator returns `True` only when **both** conditions are true. For example, the expression below is `True` only if `x` is greater than `0` **and** less than `10`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "8b457abd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 5\n",
    "x > 0 and x < 10"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebd06ba2",
   "metadata": {},
   "source": [
    "The following expression is `True` if **either or** both* of the conditions is true, that is, if the number is divisible by 2 *or* 3:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "543d8ce4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x % 2 == 0 or x % 3 == 0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2990df6a",
   "metadata": {},
   "source": [
    "Finally, the `not` operator negates a boolean expression, so the following expression is `True` if `x > y` is `False`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3cd8db9f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "not x > y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d573244",
   "metadata": {},
   "source": [
    "### Truthy/Falsy\n",
    "\n",
    "Strictly speaking, the operands of a logical operator should be **boolean expressions**, but Python is not very strict: Every value has an inherent Boolean evaluation, which can either be considered True or False in a Boolean context. Values that evaluate to True are called truthy, and values that evaluate to False are called falsy.\n",
    "\n",
    "- **Truthy** values: \n",
    "  - Any **nonzero** number\n",
    "  - Non-empty sequences or collections: e.g., **string**, list, dictionary\n",
    "  - Constant: True\n",
    "- **Flasy** values: \n",
    "  - Empty sequences and collections\n",
    "  - **Zero** value numbers: 0, 0.0, 0j\n",
    "  - Constants: `None`, False\n",
    "\n",
    "This flexibility can be useful, but there are subtleties that can be confusing. So, while you need to know what how it works, you might want to avoid using it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b5670384",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "True\n",
      "False\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "print(bool('42'))        ### how can a string be True??? ==> It is in Python.\n",
    "print(42 and True)       ### 42 is true and True if of course True; numbers are True if they are not zero.\n",
    "print('42' and True)     ### True and True\n",
    "\n",
    "print(bool(0))\n",
    "s1 = \"  \"\n",
    "s2 = \"\"\n",
    "print(bool(s1))\n",
    "print(bool(s2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a6f4de7",
   "metadata": {},
   "source": [
    "Instead of this:\n",
    "```python\n",
    "if len(my_list) > 0:\n",
    "    print(\"Has elements\")\n",
    "```\n",
    "use this:\n",
    "```python\n",
    "if my_list:\n",
    "    print(\"Has elements\")\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02d547ab",
   "metadata": {},
   "source": [
    "Or, **[short-circuit evaluation](https://www.geeksforgeeks.org/c/short-circuit-evaluation-in-programming/)**:\n",
    "(Short-circuit evaluation is \"the semantics of some Boolean operators in some programming languages in which the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression: when the first argument of the AND function evaluates to false, the overall value must be false; and when the first argument of the OR function evaluates to true, the overall value must be true {cite}`wikipedia_2026`.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83e8e08c",
   "metadata": {},
   "source": [
    "Or, **[short-circuit evaluation](https://www.geeksforgeeks.org/c/short-circuit-evaluation-in-programming/)**:\n",
    "(Short-circuit evaluation is \"the semantics of some Boolean operators in some programming languages in which the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression: when the first argument of the AND function evaluates to false, the overall value must be false; and when the first argument of the OR function evaluates to true, the overall value must be true {cite}`wikipedia_2026`.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "148b46b4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "default\n"
     ]
    }
   ],
   "source": [
    "result = \"\" or \"default\"\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "511c0d6e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "What? This is True\n"
     ]
    }
   ],
   "source": [
    "if 3333:\n",
    "    print(\"What? This is True\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ee8567c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Empty string is falsy\n"
     ]
    }
   ],
   "source": [
    "if \"\":\n",
    "    print(\"Runs\")\n",
    "else:\n",
    "    print(\"Empty string is falsy\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fc63c6a3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "### Exercise: what's the output?\n",
    "\n",
    "a = 6\n",
    "b = 10\n",
    "print( not (b == 6) )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5bef7ae1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "### Exercise: what's the output?\n",
    "\n",
    "a = 6\n",
    "b = 10\n",
    "print( a == 10 or b == 10 )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e07d9d8",
   "metadata": {},
   "source": [
    "### Membership Operators\n",
    "\n",
    "In Python, membership means checking whether a value is present in a **container**/**collection** type (such as list, tuple dictionary, set, string) object. Python provides two membership operators:\n",
    "- `in`\n",
    "- `not in`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4be54ee9",
   "metadata": {},
   "source": [
    "Use the membership operators, `in` and `not in`, to check whether a value is in a collection.\n",
    "\n",
    "| Operator | Type | Example | Description |\n",
    "|----------|------|---------|-------------|\n",
    "| `in` | Membership | `3 in [1,2,3]` | Is value inside collection? |\n",
    "| `not in` | Non-membership | `4 not in [1,2,3]` | Is value NOT inside collection? |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1979463d",
   "metadata": {},
   "source": [
    "Let's check the membership of some elements in containers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "30df06dc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "True\n",
      "True\n",
      "False\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "numbers = [2, 1, 3, 4, 7]\n",
    "\n",
    "# Check if value is in the list\n",
    "print(3 in numbers)        # True\n",
    "print(10 in numbers)       # False\n",
    "print(10 not in numbers)   # True\n",
    "\n",
    "# Works with strings too\n",
    "name = \"Chen\"\n",
    "print(\"C\" in name)         # True\n",
    "print(\"z\" in name)         # False\n",
    "\n",
    "# Works with dictionaries (checks keys)\n",
    "person = {\"name\": \"Chen\", \"age\": 25}\n",
    "print(\"name\" in person)    # True\n",
    "print(\"Chen\" in person)    # False (it's a value, not a key)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b57ab0e8",
   "metadata": {},
   "source": [
    "### Identity Operators\n",
    "\n",
    "Identity operators test whether two variables refer to the **same object in memory** — not just whether they have equal values. This is a subtle but important distinction from `==`.\n",
    "\n",
    "| Operator  | Description                               | Example          |\n",
    "|-----------|-------------------------------------------|------------------|\n",
    "| `is`      | return `True` if both point to the same object   | `a is None`      |\n",
    "| `is not`  | return `True` if they point to different objects | `a is not None`  |\n",
    "\n",
    "> **Key difference**: `==` checks if values are equal; `is` checks if they are the *same object* (same memory address).  \n",
    "> Use `is` mainly for comparing against `None`, `True`, or `False`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "9965a7aa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "True\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "a = [1, 2, 3]\n",
    "b = [1, 2, 3]\n",
    "c = a\n",
    "\n",
    "print(a == b)       # True  — same values\n",
    "print(a is b)       # False — different objects in memory\n",
    "print(a is c)       # True  — c points to the same object as a\n",
    "\n",
    "# Most common use: check for None\n",
    "x = None\n",
    "print(x is None)    # True  (preferred over x == None)\n",
    "print(x is not None)  # False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50cb1480",
   "metadata": {},
   "source": [
    "## Bitwise Operations\n",
    "\n",
    "Bitwise operations are used for low-level programming tasks that require efficient memory manipulation of individual bits, such as optimizing arithmetic operations, flagging file permissions, and hashing. \n",
    "\n",
    "For an example of Bitwise operations, let's take a look at Bitwise `AND(&)`. The bitwise `AND` operation returns 1 only if both bits are 1. Here we have numbers A (0011, decimal 3) and B (0101, or 5 in decimal). As seen in the Truth Table below, we have `1` (`0001`) as the result of this Bitwise AND (`&`) operation:\n",
    "\n",
    "**Truth Table**:\n",
    "A | B | A & B\n",
    "--|---|------\n",
    "0 | 0 |  0\n",
    "0 | 1 |  0\n",
    "1 | 0 |  0\n",
    "1 | 1 |  1\n",
    "\n",
    "**Bitwise Operation Examples**\n",
    "\n",
    "| No. | Operator | Name       | Example      | Result | Explanation                                                   |\n",
    "|-----|----------|------------|--------------|--------|---------------------------------------------------------------|\n",
    "| 1   | `&`      | AND        | `5 & 3`      | `1`    | Returns 1 only when both bits are 1 (5=0101, 3=0011 → 0001)  |\n",
    "| 2   | `\\|`     | OR         | `5 \\| 3`     | `7`    | Returns 1 when at least one bit is 1 (5=0101, 3=0011 → 0111) |\n",
    "| 3   | `^`      | XOR        | `5 ^ 3`      | `6`    | Returns 1 when bits are different (5=0101, 3=0011 → 0110)    |\n",
    "| 4   | `~`      | NOT        | `~5`         | `-6`   | Inverts all bits in two's complement representation          |\n",
    "| 5   | `<<`     | Left shift | `5 << 1`     | `10`   | Shifts bits left, adding 0s on right; multiply by 2          |\n",
    "| 6   | `>>`     | Right shift| `5 >> 1`     | `2`    | Shifts bits right, removing rightmost bits; divide by 2      |\n",
    "\n",
    "The code looks like below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "e41c2b45",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "7\n",
      "6\n",
      "-6\n",
      "10\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "a = 5   # binary 0101\n",
    "b = 3   # binary 0011\n",
    "\n",
    "bw1 = a & b   # 1  (binary 0001)\n",
    "bw2 = a | b   # 7  (binary 0111)\n",
    "bw3 = a ^ b   # 6  (binary 0110)\n",
    "bw4 = ~a      # -6 (two's complement)\n",
    "bw5 = a << 1  # 10 (binary 1010)\n",
    "bw6 = a >> 1  # 2  (binary 10)\n",
    "\n",
    "print(bw1, bw2, bw3, bw4, bw5, bw6, sep='\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "232d0037",
   "metadata": {},
   "source": [
    "As an example, we can use the bitwise operation to check if a number is even because if a binary number's last digit is 0, then it is an even number:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "9f8967bd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False False True True\n"
     ]
    }
   ],
   "source": [
    "def is_even(n):\n",
    "    return (n & 1) == 0\n",
    "\n",
    "x = is_even(3)       ### 011\n",
    "y = is_even(5)       ### 101\n",
    "z = is_even(6)       ### 110\n",
    "z2 = is_even(8)      ### 1000\n",
    "print(x, y, z, z2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4bb74542",
   "metadata": {},
   "source": [
    "As another example, when Linux/UNIX systems check if a user has write permission as an owner:\n",
    "\n",
    "```bash\n",
    "110                        ### (rw-)\n",
    "010                        ### (w)\n",
    "---\n",
    "010                        ### not zero → write exists \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "682a0c91",
   "metadata": {},
   "source": [
    "Or, for getting a network address using bitwise AND (&):\n",
    "\n",
    "```bash\n",
    "IP:         192.168.010.025  -> 11000000.10101000.00001010.00011001\n",
    "Subnet:     255.255.255.0    -> 11111111.11111111.11111111.00000000\n",
    "\n",
    "11000000.10101000.00001010.00011001   (IP)\n",
    "11111111.11111111.11111111.00000000   (MASK)\n",
    "-----------------------------------\n",
    "11000000.10101000.00001010.00000000   (NETWORK)\n",
    "\n",
    "Network Address: 192.168.10.0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "191bcd02-a6eb-4d0f-9f38-79891541af6a",
   "metadata": {},
   "source": [
    "## Operator Precedence\n",
    "\n",
    "Operator precedence determines the order in which operations are evaluated in an expression. Operations with higher precedence are performed before those with lower precedence. When in doubt, use the parentheses `()` to ensure you have the preferred precedence.\n",
    "\n",
    "Notice that exponentiation happens before addition because exponentiation is the 2nd highest precedence. This actually follows the order of operations you might have learned in a math class: exponentiation happens before multiplication and division, which happen before addition and subtraction."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f4b6fb1",
   "metadata": {},
   "source": [
    "Below is a comprehensive list of operator precedence:\n",
    "\n",
    "| **Precedence Level** | **Operator(s)**                                              | **Description / Example**                         |                         |\n",
    "| -------------------- | ------------------------------------------------------------ | ------------------------------------------------- | ----------------------- |\n",
    "| 1 (Highest)      | `()`                                                         | Parentheses — control order of evaluation         |                         |\n",
    "| 2                | `**`                                                         | Exponentiation                                    |                         |\n",
    "| 3                | `+x`, `-x`, `~x`                                             | Unary plus, unary minus, bitwise NOT              |                         |\n",
    "| 4                | `*`, `/`, `//`, `%`                                          | Multiplication, division, floor division, modulus |                         |\n",
    "| 5                | `+`, `-`                                                     | Addition, subtraction                             |                         |\n",
    "| 6                | `<<`, `>>`                                                   | Bitwise left and right shift                      |                         |\n",
    "| 7                | `&`                                                          | Bitwise AND                                       |                         |\n",
    "| 8                | `^`, `\\|`                                                 | Bitwise XOR, bitwise OR |\n",
    "| 9                | Comparison: `<`, `<=`, `>`, `>=`, `!=`, `==`                 | Relational and equality checks                    |                         |\n",
    "| 10               | `is`, `is not`, `in`, `not in`                               | Identity and membership operators                 |                         |\n",
    "| 11               | `not`                                                        | Logical NOT                                       |                         |\n",
    "| 12               | `and`                                                        | Logical AND                                       |                         |\n",
    "| 13               | `or`                                                         | Logical OR                                        |                         |\n",
    "| 14 (Lowest)      | Assignment: `=`, `+=`, `-=`, `*=`, `/=`, `//=`, `%=` , `**=` | Assignment and augmented assignment               |                         |\n",
    "\n",
    "Note:\n",
    "- **Always use parentheses** when precedence is unclear to improve code readability\n",
    "- **Exponentiation** (`**`) is evaluated right-to-left: `2 ** 3 ** 2` equals `2 ** 9` = `512`\n",
    "- **Comparison operators** all have the same precedence and are evaluated left-to-right\n",
    "- **Logical operators** follow the order: `not` → `and` → `or`\n",
    "- When operators have the same precedence, they are typically evaluated left-to-right (left-associative), except for exponentiation which is right-associative."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc8da43f-276d-4ee7-b470-376e78506406",
   "metadata": {},
   "source": [
    "In the following example, multiplication happens before addition, and exponentiation happens before multiplication. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "4d431206",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19\n"
     ]
    }
   ],
   "source": [
    "num1 = 12 + 5 * 6\n",
    "num2 = (12 + 5) * 6\n",
    "\n",
    "x, y, z = 1, 2, 3\n",
    "\n",
    "result = x + y * z ** 2\n",
    "print(result)               ### output: 13"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "c7517a07-c2fa-44bb-9a27-f2d3a113864e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "True\n",
      "True\n",
      "False\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "numbers = [2, 1, 3, 4, 7]\n",
    "\n",
    "# Check if value is in the list\n",
    "print(3 in numbers)        # True\n",
    "print(10 in numbers)       # False\n",
    "print(10 not in numbers)   # True\n",
    "\n",
    "# Works with strings too\n",
    "name = \"Chen\"\n",
    "print(\"C\" in name)         # True\n",
    "print(\"z\" in name)         # False\n",
    "\n",
    "# Works with dictionaries (checks keys)\n",
    "person = {\"name\": \"Chen\", \"age\": 25}\n",
    "print(\"name\" in person)    # True\n",
    "print(\"Chen\" in person)    # False (it's a value, not a key)"
   ]
  }
 ],
 "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
}
