diff --git a/14-Advanced Python Objects and Data Structures/08-BONUS - With Statement Context Managers.ipynb b/14-Advanced Python Objects and Data Structures/08-BONUS - With Statement Context Managers.ipynb new file mode 100644 index 000000000..c228b09fb --- /dev/null +++ b/14-Advanced Python Objects and Data Structures/08-BONUS - With Statement Context Managers.ipynb @@ -0,0 +1,236 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# With Statement Context Managers\n", + "\n", + "When you open a file using `f = open('test.txt')`, the file stays open until you specifically call `f.close()`. Should an exception be raised while working with the file, it remains open. This can lead to vulnerabilities in your code, and inefficient use of resources.\n", + "\n", + "A context manager handles the opening and closing of resources, and provides a built-in `try/finally` block should any exceptions occur.\n", + "\n", + "The best way to demonstrate this is with an example.\n", + "\n", + "### Standard `open()` procedure, with a raised exception:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "ename": "UnsupportedOperation", + "evalue": "not readable", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mUnsupportedOperation\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mp\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'oops.txt'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;34m'a'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mreadlines\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[0mp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mUnsupportedOperation\u001b[0m: not readable" + ] + } + ], + "source": [ + "p = open('oops.txt','a')\n", + "p.readlines()\n", + "p.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see if we can modify our file:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "13" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p.write('add more text')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ouch! I may not have wanted to do that until I traced the exception! Unfortunately, the exception prevented the last line, `p.close()` from running. Let's close the file manually:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "p.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Protect the file with `try/except/finally`\n", + "\n", + "A common workaround is to insert a `try/except/finally` clause to close the file whenever an exception is raised:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "An exception was raised!\n" + ] + } + ], + "source": [ + "p = open('oops.txt','a')\n", + "try:\n", + " p.readlines()\n", + "except:\n", + " print('An exception was raised!')\n", + "finally:\n", + " p.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see if we can modify our file this time:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "I/O operation on closed file.", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'add more text'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mValueError\u001b[0m: I/O operation on closed file." + ] + } + ], + "source": [ + "p.write('add more text')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Excellent! Our file is safe.\n", + "\n", + "### Save steps with `with`\n", + "\n", + "Now we'll employ our context manager. The syntax follows `with [resource] as [target]: do something`" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "ename": "UnsupportedOperation", + "evalue": "not readable", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mUnsupportedOperation\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'oops.txt'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;34m'a'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mp\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mreadlines\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mUnsupportedOperation\u001b[0m: not readable" + ] + } + ], + "source": [ + "with open('oops.txt','a') as p:\n", + " p.readlines()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Can we modify the file?" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "ename": "ValueError", + "evalue": "I/O operation on closed file.", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'add more text'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;31mValueError\u001b[0m: I/O operation on closed file." + ] + } + ], + "source": [ + "p.write('add more text')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great! With just one line of code we've handled opening the file, enclosing our code in a `try/finally` block, and closing our file all at the same time.\n", + "\n", + "Now you should have a basic understanding of context managers." + ] + } + ], + "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.6.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}