{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "73703282",
   "metadata": {},
   "source": [
    "## Lecture 16, 13 October 2026"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bea293f4-1fbf-4aa7-b938-4804202ab573",
   "metadata": {},
   "source": [
    "### Exception handling"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3af91f18-45fc-4880-857c-16c069f14cdf",
   "metadata": {},
   "source": [
    "- Example with `input()`\n",
    "- Python statement `pass` is a do-nothing placeholder. Cannot omit `except:` block, nor can you have an empty block."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5d3ea09-a024-44b7-8cd8-a06ec77ea7e7",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "834ef1e9-fe01-45c6-b023-1983f455372d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  abcd\n",
      "Enter a number:  xyz\n",
      "Enter a number:  90\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "90\n"
     ]
    }
   ],
   "source": [
    "invalid = True\n",
    "while (invalid):\n",
    "    try:\n",
    "        xstr = input(\"Enter a number: \")\n",
    "        xint = int(xstr)\n",
    "        invalid = False\n",
    "    except:\n",
    "        pass\n",
    "print(xint)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "a1cdf5c3-8698-4e79-95da-15c191112333",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  abcd\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Try again:\n"
     ]
    },
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  xyz\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Try again:\n"
     ]
    },
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  uvw\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Try again:\n"
     ]
    },
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  32\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "32\n"
     ]
    }
   ],
   "source": [
    "invalid = True\n",
    "tryagain = False\n",
    "while (invalid):\n",
    "    try:\n",
    "        if tryagain:\n",
    "            print(\"Try again:\")\n",
    "        xstr = input(\"Enter a number: \")\n",
    "        xint = int(xstr)\n",
    "        invalid = False\n",
    "    except:\n",
    "        tryagain = True\n",
    "print(xint)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a073f234-181a-47b9-8f39-43a0c259f7a5",
   "metadata": {},
   "source": [
    "- Catch a specific type of exception"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "9a1a0f36-ff84-4533-9e0a-5312cb68a072",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "invalid literal for int() with base 10: 'abc'",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[4]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m int(\u001b[33m\"abc\"\u001b[39m)\n",
      "\u001b[31mValueError\u001b[39m: invalid literal for int() with base 10: 'abc'"
     ]
    }
   ],
   "source": [
    "int(\"abc\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "fdaa4a37-5c54-4153-9983-2bd118dd9186",
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Enter a number:  abc\n",
      "Enter a number:  39\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "39\n"
     ]
    }
   ],
   "source": [
    "invalid = True\n",
    "while (invalid):\n",
    "    try:\n",
    "        xstr = input(\"Enter a number: \")\n",
    "        xint = int(xstr)\n",
    "        invalid = False\n",
    "    except ValueError:\n",
    "        pass\n",
    "print(xint)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c0384c6-ef60-4ce2-a1e6-05a0af37c219",
   "metadata": {},
   "source": [
    "#### String formatting"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6a2ff97-94b8-40e8-85b5-9e38e9f4d399",
   "metadata": {},
   "source": [
    "- Positional arguments"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "db4ff1ce-f4ab-44c4-abbb-66f048be7edf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'First one is 17, second one is 52'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 17\n",
    "y = 52\n",
    "message = \"First one is {0}, second one is {1}\"\n",
    "message.format(x,y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "38978bd8-8aa9-499c-9679-457cfccd20c6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'First one is 52, second one is 17'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 17\n",
    "y = 52\n",
    "message = \"First one is {1}, second one is {0}\"\n",
    "message.format(x,y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "851bb7d6-0709-49c5-97d0-c68735cea9cf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'S one is 52, second one is 17. To repeat, first one is 52.'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = 17\n",
    "y = 52\n",
    "message1 = \"S one is {1}, second one is {0}. To repeat, first one is {1}.\"\n",
    "message1.format(x,y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e9e387d-9c2b-44b3-8c32-21a307db12de",
   "metadata": {},
   "source": [
    "- Raising an exception in `List()`\n",
    "- Inserting a negative value raises `ValueError`\n",
    "- Use string formatting to add negative value to error message"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "3f7a6da5-1fdd-4553-9d7d-5818d77aef25",
   "metadata": {},
   "outputs": [],
   "source": [
    "class List:\n",
    "    def __init__(self,initlist = []):\n",
    "        self.value = None\n",
    "        self.next = None\n",
    "        for x in initlist:\n",
    "            self.append(x)\n",
    "        return\n",
    "\n",
    "    def isempty(self):\n",
    "        return(self.value == None)\n",
    "    \n",
    "    def appendi(self,v):   # append, iterative\n",
    "        if v < 0:\n",
    "            raise ValueError(\"Negative input:{0}\".format(v))\n",
    "        if self.isempty():\n",
    "            self.value = v\n",
    "            return\n",
    "        \n",
    "        temp = self\n",
    "        while temp.next != None:\n",
    "            temp = temp.next\n",
    "\n",
    "        temp.next = List()\n",
    "        temp.next.value = v \n",
    "        return\n",
    "\n",
    "    def appendr(self,v):   # append, recursive\n",
    "        if v < 0:\n",
    "            raise ValueError(\"Negative input:{0}\".format(v))\n",
    "        if self.isempty():\n",
    "            self.value = v\n",
    "        elif self.next == None:\n",
    "            self.next = List([v])\n",
    "        else:\n",
    "            self.next.appendr(v)\n",
    "        return\n",
    "\n",
    "    def append(self,v):\n",
    "        self.appendr(v)\n",
    "        return\n",
    "\n",
    "    def insert(self,v):\n",
    "        if v < 0:\n",
    "            raise ValueError(\"Negative input:{0}\".format(v))\n",
    "        if self.isempty():\n",
    "            self.value = v\n",
    "            return\n",
    "\n",
    "        newnode = List()\n",
    "        newnode.value = v\n",
    "        \n",
    "        # Exchange values in self and newnode\n",
    "        (self.value, newnode.value) = (newnode.value, self.value)\n",
    "\n",
    "        # Switch links\n",
    "        (self.next, newnode.next) = (newnode, self.next)\n",
    "\n",
    "        return\n",
    "\n",
    "    def delete(self,v):   # delete, recursive\n",
    "        if self.isempty():\n",
    "            return\n",
    "\n",
    "        if self.value == v:\n",
    "            self.value = None\n",
    "            if self.next != None:\n",
    "                self.value = self.next.value\n",
    "                self.next = self.next.next\n",
    "            return\n",
    "        else:\n",
    "            if self.next != None:\n",
    "                self.next.delete(v)\n",
    "                if self.next.value == None:\n",
    "                    self.next = None\n",
    "        return\n",
    "    \n",
    "    def __str__(self):\n",
    "        # Iteratively create a Python list from linked list\n",
    "        # and convert that to a string\n",
    "        selflist = []\n",
    "        if self.isempty():\n",
    "            return(str(selflist))\n",
    "\n",
    "        temp = self\n",
    "        selflist.append(temp.value)\n",
    "        \n",
    "        while temp.next != None:\n",
    "          temp = temp.next\n",
    "          selflist.append(temp.value)\n",
    "\n",
    "        return(str(selflist))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "064e26ad-9096-48fe-a714-f5396d68a931",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "Negative input:-2",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[10]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m l = List([\u001b[32m1\u001b[39m,-\u001b[32m2\u001b[39m,\u001b[32m3\u001b[39m])\n\u001b[32m      2\u001b[39m print(l)\n",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[9]\u001b[39m\u001b[32m, line 6\u001b[39m, in \u001b[36mList.__init__\u001b[39m\u001b[34m(self, initlist)\u001b[39m\n\u001b[32m      2\u001b[39m     \u001b[38;5;28;01mdef\u001b[39;00m __init__(self,initlist = []):\n\u001b[32m      3\u001b[39m         self.value = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m      4\u001b[39m         self.next = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m      5\u001b[39m         \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;28;01min\u001b[39;00m initlist:\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m             self.append(x)\n\u001b[32m      7\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m\n",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[9]\u001b[39m\u001b[32m, line 39\u001b[39m, in \u001b[36mList.append\u001b[39m\u001b[34m(self, v)\u001b[39m\n\u001b[32m     38\u001b[39m     \u001b[38;5;28;01mdef\u001b[39;00m append(self,v):\n\u001b[32m---> \u001b[39m\u001b[32m39\u001b[39m         self.appendr(v)\n\u001b[32m     40\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m\n",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[9]\u001b[39m\u001b[32m, line 29\u001b[39m, in \u001b[36mList.appendr\u001b[39m\u001b[34m(self, v)\u001b[39m\n\u001b[32m     27\u001b[39m     \u001b[38;5;28;01mdef\u001b[39;00m appendr(self,v):   \u001b[38;5;66;03m# append, recursive\u001b[39;00m\n\u001b[32m     28\u001b[39m         \u001b[38;5;28;01mif\u001b[39;00m v < \u001b[32m0\u001b[39m:\n\u001b[32m---> \u001b[39m\u001b[32m29\u001b[39m             \u001b[38;5;28;01mraise\u001b[39;00m ValueError(\u001b[33m\"Negative input:{0}\"\u001b[39m.format(v))\n\u001b[32m     30\u001b[39m         \u001b[38;5;28;01mif\u001b[39;00m self.isempty():\n\u001b[32m     31\u001b[39m             self.value = v\n\u001b[32m     32\u001b[39m         \u001b[38;5;28;01melif\u001b[39;00m self.next == \u001b[38;5;28;01mNone\u001b[39;00m:\n",
      "\u001b[31mValueError\u001b[39m: Negative input:-2"
     ]
    }
   ],
   "source": [
    "l = List([1,-2,3])\n",
    "print(l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "7e35ebac-85b0-44b2-bcc3-65b9e5818500",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ValueError reported: Negative input:-2\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    l = List([1,-2,3])\n",
    "except ValueError as errormsg:\n",
    "    print(\"ValueError reported:\",errormsg)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4476d5f-f394-40dc-a8c3-222eea54f225",
   "metadata": {},
   "source": [
    "- String formatting with output specification"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "073cfee7-bbbe-4600-b01c-3dd44683e9f7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Value   747.30'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"Value {0:8.2f}\".format(747.3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "ccae5580-1697-46e6-b659-8d562d7aa518",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Value 99999999947.34         99999999947.3444061      22'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"Value {0:6.2f} {0:27.7f} {1:7d}\".format(99999999947.3444,22)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "22960b9b-48cf-4248-8740-5d1cf43f65f5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Value 99999999947.34         99999999947.3444061 0000022'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"Value {0:6.2f} {0:27.7f} {1:07d}\".format(99999999947.3444,22)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68cc7047-6fab-4fb9-9ef9-273b257160db",
   "metadata": {},
   "source": [
    "- Alternative use case for exceptions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "871cc20e-3c33-462c-a837-00134ae61621",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'k': 6}\n"
     ]
    }
   ],
   "source": [
    "d = {}\n",
    "for i in range(1,4):\n",
    "    try:\n",
    "        d[\"k\"] = d[\"k\"] + i\n",
    "    except KeyError:\n",
    "        d[\"k\"] = i\n",
    "print(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "fc7f09f1-5eec-491f-b659-2bd4997996c4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'k': [1, 2, 3]}\n"
     ]
    }
   ],
   "source": [
    "d = {}\n",
    "for i in range(1,4):\n",
    "    try:\n",
    "        d[\"k\"].append(i)\n",
    "    except KeyError:\n",
    "        d[\"k\"] = [i]\n",
    "print(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2373c175",
   "metadata": {},
   "source": [
    "### Working with files"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1ff2150",
   "metadata": {},
   "source": [
    "#### Reading files"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c894c91",
   "metadata": {},
   "source": [
    "- Open a file in mode `\"r\"`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "d10ba375",
   "metadata": {},
   "outputs": [],
   "source": [
    "fh = open(\"oz.txt\",\"r\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0b07cf3",
   "metadata": {},
   "source": [
    "- `read()` returns a string with the entire file\n",
    "- Note the `\\n` characters indicating end of line (\"new line\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "091e5a89",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'I met a traveller from an antique land\\nWho said: Two vast and trunkless legs of stone\\nStand in the desaet. Near them, on the sand,\\nHalf sunk, a shattered visage lies, whose frown,\\nAnd wrinkled lip, and sneer of cold command,\\nTell that its sculptor well those passions read\\nWhich yet survive, stamped on these lifeless things,\\nThe hand that mocked them and the heart that fed:\\nAnd on the pedestal these words appear:\\n\"My name is Ozymandias, King of Kings:\\nLook on my works, ye Mighty, and despair!\"\\nNo thing beside remains. Round the decay\\nOf that colossal wreck, boundless and bare\\nThe lone and level sands stretch far away. \\n'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "contents = fh.read()\n",
    "contents"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4bbcc920",
   "metadata": {},
   "source": [
    "- After reading the file, we are at the end\n",
    "- End of file is indicated by `read()` returning the empty string"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "8f263551",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "''"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fh.read()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "458dda06-887f-4bc4-9581-57ed5e6e619a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "''"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fh.read()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b195f342",
   "metadata": {},
   "source": [
    "- To re-read the file, we have to close it and open it again"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "42e89464",
   "metadata": {},
   "outputs": [],
   "source": [
    "fh.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d165563b",
   "metadata": {},
   "source": [
    "- `readline()` reads one line\n",
    "- Unlike `input()`, the line that is read includes the terminating `\\n'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "5e8201d3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'I met a traveller from an antique land\\n'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fh = open(\"oz.txt\",\"r\")\n",
    "line1 = fh.readline()\n",
    "line1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9565ded2",
   "metadata": {},
   "source": [
    "- `readlines()` returns the entire file as a list of lines\n",
    "- Each line is terminated by `\\n`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "4db098e5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['I met a traveller from an antique land\\n',\n",
       " 'Who said: Two vast and trunkless legs of stone\\n',\n",
       " 'Stand in the desaet. Near them, on the sand,\\n',\n",
       " 'Half sunk, a shattered visage lies, whose frown,\\n',\n",
       " 'And wrinkled lip, and sneer of cold command,\\n',\n",
       " 'Tell that its sculptor well those passions read\\n',\n",
       " 'Which yet survive, stamped on these lifeless things,\\n',\n",
       " 'The hand that mocked them and the heart that fed:\\n',\n",
       " 'And on the pedestal these words appear:\\n',\n",
       " '\"My name is Ozymandias, King of Kings:\\n',\n",
       " 'Look on my works, ye Mighty, and despair!\"\\n',\n",
       " 'No thing beside remains. Round the decay\\n',\n",
       " 'Of that colossal wreck, boundless and bare\\n',\n",
       " 'The lone and level sands stretch far away. \\n']"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fh.close()\n",
    "fh = open(\"oz.txt\",\"r\")\n",
    "alllines = fh.readlines()\n",
    "alllines"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e33c938",
   "metadata": {},
   "source": [
    "- `readlines()` returns the lines from the current position\n",
    "- In the following example, the list returned is from the second line onwards"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "63b77307",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Who said: Two vast and trunkless legs of stone\\n',\n",
       " 'Stand in the desaet. Near them, on the sand,\\n',\n",
       " 'Half sunk, a shattered visage lies, whose frown,\\n',\n",
       " 'And wrinkled lip, and sneer of cold command,\\n',\n",
       " 'Tell that its sculptor well those passions read\\n',\n",
       " 'Which yet survive, stamped on these lifeless things,\\n',\n",
       " 'The hand that mocked them and the heart that fed:\\n',\n",
       " 'And on the pedestal these words appear:\\n',\n",
       " '\"My name is Ozymandias, King of Kings:\\n',\n",
       " 'Look on my works, ye Mighty, and despair!\"\\n',\n",
       " 'No thing beside remains. Round the decay\\n',\n",
       " 'Of that colossal wreck, boundless and bare\\n',\n",
       " 'The lone and level sands stretch far away. \\n']"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fh.close()\n",
    "fh = open(\"oz.txt\",\"r\")\n",
    "line1 = fh.readline()      # Read first line\n",
    "alllines = fh.readlines()  # From second line onwards\n",
    "alllines"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8cb72b87",
   "metadata": {},
   "source": [
    "#### Stripping white space"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0a39180",
   "metadata": {},
   "source": [
    "- We can strip off leading and trailing \"white space\" (blank, tab, newline) from a string\n",
    "- `rstrip()` removes trailing whitespace\n",
    "- Note that strings are immutable, so the function returns a new string, leaving the original untouched"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "eecfeaf4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'   abc    \\n'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "teststr = \"   abc    \\n\"\n",
    "teststr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "14df3215",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'   abc'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "teststr.rstrip()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "1d19792e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'   abc    \\n'"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "teststr"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4972cac",
   "metadata": {},
   "source": [
    "- `lstrip()` removes leading whitespace"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "22bcae5f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'abc    \\n'"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "teststr.lstrip()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6bfd2b5",
   "metadata": {},
   "source": [
    "- `strip()` removes whitespace at both ends"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "d28ffad5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'abc'"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "teststr.strip()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6011298",
   "metadata": {},
   "source": [
    "- Can use these to quickly remove `\\n` from lines that we read from a file\n",
    "- In the first loop below, there is a blank line between actual lines because of the `\\n` in the input line followed by the newline inserted by `print()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "f6821ec7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I met a traveller from an antique land\n",
      "\n",
      "Who said: Two vast and trunkless legs of stone\n",
      "\n",
      "Stand in the desaet. Near them, on the sand,\n",
      "\n",
      "Half sunk, a shattered visage lies, whose frown,\n",
      "\n",
      "And wrinkled lip, and sneer of cold command,\n",
      "\n",
      "Tell that its sculptor well those passions read\n",
      "\n",
      "Which yet survive, stamped on these lifeless things,\n",
      "\n",
      "The hand that mocked them and the heart that fed:\n",
      "\n",
      "And on the pedestal these words appear:\n",
      "\n",
      "\"My name is Ozymandias, King of Kings:\n",
      "\n",
      "Look on my works, ye Mighty, and despair!\"\n",
      "\n",
      "No thing beside remains. Round the decay\n",
      "\n",
      "Of that colossal wreck, boundless and bare\n",
      "\n",
      "The lone and level sands stretch far away. \n",
      "\n"
     ]
    }
   ],
   "source": [
    "fh.close()\n",
    "fh = open(\"oz.txt\",\"r\")\n",
    "for l in fh.readlines():\n",
    "    print(l)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b64063b1",
   "metadata": {},
   "source": [
    "- If we strip each line before printing, the blank lines are eliminated"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "14e8793e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I met a traveller from an antique land\n",
      "Who said: Two vast and trunkless legs of stone\n",
      "Stand in the desaet. Near them, on the sand,\n",
      "Half sunk, a shattered visage lies, whose frown,\n",
      "And wrinkled lip, and sneer of cold command,\n",
      "Tell that its sculptor well those passions read\n",
      "Which yet survive, stamped on these lifeless things,\n",
      "The hand that mocked them and the heart that fed:\n",
      "And on the pedestal these words appear:\n",
      "\"My name is Ozymandias, King of Kings:\n",
      "Look on my works, ye Mighty, and despair!\"\n",
      "No thing beside remains. Round the decay\n",
      "Of that colossal wreck, boundless and bare\n",
      "The lone and level sands stretch far away.\n"
     ]
    }
   ],
   "source": [
    "fh.close()\n",
    "fh = open(\"oz.txt\",\"r\")\n",
    "for l in fh.readlines():\n",
    "    print(l.rstrip())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "87438999",
   "metadata": {},
   "source": [
    "#### Writing files"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9d57ac3",
   "metadata": {},
   "source": [
    "- Open a file in mode `\"w\"`\n",
    "- Opening a non-existent file for reading generates an error\n",
    "- Opening a non-existent file for writing creates a new file\n",
    "- If the file already exists, write will overwrite the contents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "d4c84ad4",
   "metadata": {},
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "[Errno 2] No such file or directory: 'newfile.txt'",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mFileNotFoundError\u001b[39m                         Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[32]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m infile = open(\u001b[33m\"newfile.txt\"\u001b[39m,\u001b[33m\"r\"\u001b[39m)\n",
      "\u001b[31mFileNotFoundError\u001b[39m: [Errno 2] No such file or directory: 'newfile.txt'"
     ]
    }
   ],
   "source": [
    "infile = open(\"newfile.txt\",\"r\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "364356fa",
   "metadata": {},
   "outputs": [],
   "source": [
    "outfile = open(\"newfile.txt\",\"w\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "ca6379dc",
   "metadata": {},
   "outputs": [],
   "source": [
    "outfile.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8fa93f1d",
   "metadata": {},
   "source": [
    "- `fh.write(s)` writes the string `s` to the file associated with file handle `fh`\n",
    "- Need to add `\\n` ourselves to ensure the end of line\n",
    "- `fh.writelines(sl)` writes a list of strings `ls`\n",
    "- Again, we need to ensure `\\n` is present at the end of each string in the list\n",
    "    - The name of the function is misleading\n",
    "    - It is more accurate to call it `writestrings()` since we have to insert `\\n` manually"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e02c74e0",
   "metadata": {},
   "source": [
    "- The following loop copies the input to the output\n",
    "    - Each line that is read includes the `\\n`\n",
    "    - Hence each line that is written also has the corresponding `\\n`\n",
    "- However, after this loop, typically the output file will be empty\n",
    "- Need to close the file handle for the buffer to be \"flushed\" to the disk"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "8c198b1f",
   "metadata": {},
   "outputs": [],
   "source": [
    "infile = open(\"oz.txt\",\"r\")\n",
    "outfile = open(\"newfile.txt\",\"w\")\n",
    "for l in infile.readlines():\n",
    "    outfile.write(l)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00e1728d-2dab-4022-bcbf-16a1adf7e919",
   "metadata": {},
   "source": [
    "- Check `newfile.txt`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "77715c0a-b989-49b9-8435-20d4d89246c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "outfile.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6804e2a0",
   "metadata": {},
   "source": [
    "- Close all file handles when you are done with them"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "38030353",
   "metadata": {},
   "outputs": [],
   "source": [
    "infile = open(\"oz.txt\",\"r\")\n",
    "outfile = open(\"newfile.txt\",\"w\")\n",
    "for l in infile.readlines():\n",
    "    outfile.write(l)\n",
    "infile.close()\n",
    "outfile.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a539db0",
   "metadata": {},
   "source": [
    "- We can also read all the lines into a list using `readlines()` and write them out using `writelines()`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "6f9f71ab",
   "metadata": {},
   "outputs": [],
   "source": [
    "infile = open(\"oz.txt\",\"r\")\n",
    "outfile = open(\"newfile.txt\",\"w\")\n",
    "contents = infile.readlines()\n",
    "outfile.writelines(contents)\n",
    "infile.close()\n",
    "outfile.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e062fec",
   "metadata": {},
   "source": [
    "#### Appending output"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1f9119d",
   "metadata": {},
   "source": [
    "- We can append our writes at the end of a file\n",
    "- Open the file with mode `\"a\"` instead of `\"w\"`\n",
    "- After the following, `newfile.txt` should have two copies of `oz.txt`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "5687bedf",
   "metadata": {},
   "outputs": [],
   "source": [
    "infile = open(\"oz.txt\",\"r\")\n",
    "outfile = open(\"newfile.txt\",\"a\")\n",
    "contents = infile.readlines()\n",
    "outfile.writelines(contents)\n",
    "infile.close()\n",
    "outfile.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e9a6b8b",
   "metadata": {},
   "source": [
    "- There are other functions we have not discussed\n",
    "- `fh.seek(n)` moves to position `n` in the file\n",
    "    - After reading a file, use `fh.seek(0)` to return to the start\n",
    "- `fh.read(n)` reads `n` characters from the current position"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "079522be",
   "metadata": {},
   "outputs": [],
   "source": [
    "infile = open(\"oz.txt\",\"r\")\n",
    "c1 = infile.read()\n",
    "infile.seek(7)\n",
    "c2 = infile.read(20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "b1cbe124",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'I met a traveller from an antique land\\nWho said: Two vast and trunkless legs of stone\\nStand in the desaet. Near them, on the sand,\\nHalf sunk, a shattered visage lies, whose frown,\\nAnd wrinkled lip, and sneer of cold command,\\nTell that its sculptor well those passions read\\nWhich yet survive, stamped on these lifeless things,\\nThe hand that mocked them and the heart that fed:\\nAnd on the pedestal these words appear:\\n\"My name is Ozymandias, King of Kings:\\nLook on my works, ye Mighty, and despair!\"\\nNo thing beside remains. Round the decay\\nOf that colossal wreck, boundless and bare\\nThe lone and level sands stretch far away. \\n'"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "b06b37ed",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "' traveller from an a'"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "c2"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
