{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Exceptions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exceptions which are events that can modify the *flow* of control through a program. \n", "\n", "In Python, exceptions are triggered automatically on errors, and they can be triggered and intercepted by your code.\n", "\n", "They are processed by **four** statements we’ll study in this notebook, the first of which has two variations (listed separately here) and the last of which was an optional extension until Python 2.6 and 3.0:\n", "\n", "* `try/except`:\n", " * Catch and recover from exceptions raised by Python, or by you\n", " \n", "* `try/finally`:\n", " * Perform cleanup actions, whether exceptions occur or not.\n", "\n", "* `raise`:\n", " * Trigger an exception manually in your code.\n", " \n", "* `assert`:\n", " * Conditionally trigger an exception in your code.\n", " \n", "* `with/as`:\n", " * Implement context managers in Python 2.6, 3.0, and later (optional in 2.5)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# `try/except` Statement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "try:\n", " statements # Run this main action first\n", "except name1: \n", " # Run if name1 is raised during try block\n", " statements\n", "except (name2, name3): \n", " # Run if any of these exceptions occur\n", " statements \n", "except name4 as var: \n", " # Run if name4 is raised, assign instance raised to var \n", " statements\n", "except: # Run for all other exceptions raised\n", " statements\n", "else:\n", " statements # Run if no exception was raised during try block\n", "```" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]\n" ] } ], "source": [ "list_of_numbers = [number for number in range(1, 100)]\n", "print(list_of_numbers)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Getting number at position 1 : 1\n", "Cleaning UP\n" ] } ], "source": [ "dictionary_of_numbers = {}\n", "for number in list_of_numbers:\n", " dictionary_of_numbers[number**2] = number\n", " \n", "try:\n", " index = list_of_numbers.index(2)\n", " value = dictionary_of_numbers[index]\n", "except (ValueError, KeyError):\n", " print('Error Raised, but Controlled! ')\n", "else: \n", " # This executes ONLY if no exception is raised\n", " print('Getting number at position %d : %d' % (index, value))\n", "finally:\n", " # Do cleanup operations\n", " print('Cleaning UP')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# `try/finally` Statement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The other flavor of the try statement is a specialization that has to do with finalization (a.k.a. termination) actions. If a finally clause is included in a try, Python will always run its block of statements “on the way out” of the try statement, whether an exception occurred while the try block was running or not. \n", "\n", "In it's general form, it is:\n", "\n", "```\n", "try:\n", " statements # Run this action first \n", "finally:\n", " statements # Always run this code on the way out\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# `with/as` Context Managers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python 2.6 and 3.0 introduced a new exception-related statement—the with, and its optional as clause. This statement is designed to work with context manager objects, which support a new method-based protocol, similar in spirit to the way that iteration tools work with methods of the iteration protocol. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Context Manager Intro" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basic Usage:\n", "\n", "```\n", "with expression [as variable]: \n", " with-block\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Classical Usage\n", "\n", "```python\n", "\n", "with open(r'C:\\misc\\data') as myfile: \n", " for line in myfile:\n", " print(line)\n", " # ...more code here...\n", "```\n", "\n", "... even using multiple context managers:\n", "\n", "```python\n", "with open('script1.py') as f1, open('script2.py') as f2: \n", " for (linenum, (line1, line2)) in enumerate(zip(f1, f2)):\n", " if line1 != line2:\n", " print('%s\\n%r\\n%r' % (linenum, line1, line2))\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### How it works\n", "\n", "1. The expression is evaluated,resulting in an object known as a **context manager** that must have `__enter__` and `__exit__` methods\n", "\n", "2. The context manager’s `__enter__` method is called. The value it returns is assigned to the variable in the as clause if present, or simply discarded otherwise\n", "\n", "3. The code in the nested with block is executed.\n", "\n", "4. If the with block raises an exception, the `__exit__(type,value,traceback)` method is called with the exception details. These are the same three values returned by `sys.exc_info` (Python function). If this method returns a `false` value, the exception is **re-raised**; otherwise, the exception is terminated. The exception should normally be reraised so that it is propagated outside the with statement.\n", "\n", "5. If the with block does not raise an exception, the `__exit__` method is still called, but its type, value, and traceback arguments are all passed in as `None`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Usage with Exceptions" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class TraceBlock:\n", " def message(self, arg):\n", " print('running ' + arg) \n", " \n", " def __enter__(self):\n", " print('starting with block')\n", " return self\n", " \n", " def __exit__(self, exc_type, exc_value, exc_tb):\n", " if exc_type is None: \n", " print('exited normally\\n')\n", " else:\n", " print('raise an exception! ' + str(exc_type)) \n", " return False # Propagate" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "starting with block\n", "running test 1\n", "reached\n", "exited normally\n", "\n" ] } ], "source": [ "with TraceBlock() as action: \n", " action.message('test 1')\n", " print('reached')" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "starting with block\n", "running test 2\n", "raise an exception! \n" ] }, { "ename": "TypeError", "evalue": "", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mTraceBlock\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0maction\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0maction\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'test 2'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mTypeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'not reached'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mTypeError\u001b[0m: " ], "output_type": "error" } ], "source": [ "with TraceBlock() as action: \n", " action.message('test 2') \n", " raise TypeError()\n", " print('not reached')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## User Defined Exceptions" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class AlreadyGotOne(Exception): \n", " pass\n", "\n", "def gail():\n", " raise AlreadyGotOne()" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "got exception\n" ] } ], "source": [ "try:\n", " gail()\n", "except AlreadyGotOne:\n", " print('got exception')" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "ename": "Career", "evalue": "So I became a waiter of Engineer", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mCareer\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;34m'So I became a waiter of {}'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_job\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mCareer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Engineer'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mCareer\u001b[0m: So I became a waiter of Engineer" ], "output_type": "error" } ], "source": [ "class Career(Exception):\n", " \n", " def __init__(self, job, *args, **kwargs):\n", " super(Career, self).__init__(*args, **kwargs)\n", " self._job = job\n", " \n", " def __str__(self): \n", " return 'So I became a waiter of {}'.format(self._job)\n", " \n", "raise Career('Engineer')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.5.1" } }, "nbformat": 4, "nbformat_minor": 0 }