From 9f22042812e42c28e94efefe73c36ba84b1a0372 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Mon, 28 Apr 2014 00:13:27 -0400 Subject: [PATCH 01/26] fixes and new section --- not_so_obvious_python_stuff.ipynb | 135 +++++++++++++++++++++++++----- 1 file changed, 114 insertions(+), 21 deletions(-) diff --git a/not_so_obvious_python_stuff.ipynb b/not_so_obvious_python_stuff.ipynb index c48d0de..a77f13b 100644 --- a/not_so_obvious_python_stuff.ipynb +++ b/not_so_obvious_python_stuff.ipynb @@ -1,6 +1,6 @@ { "metadata": { - "name": "", + "name": "not_so_obvious_python_stuff", "signature": "sha256:9654ab25e9d989ee8f196ec7cd5c2b7222157dbe195ddf70e6ec34329c9db545" }, "nbformat": 3, @@ -80,7 +80,8 @@ "- [Key differences between Python 2 and 3](#python_differences)\n", "- [Function annotations - What are those `->`'s in my Python code?](#function_annotation)\n", "- [Abortive statements in `finally` blocks](#finally_blocks)\n", - "- [Assigning types to variables as values](#variable_types)" + "- [Assigning types to variables as values](#variable_types)\n", + "- [Only the first clause of generators is evaluated immediately](#generator_rhs)" ] }, { @@ -274,13 +275,13 @@ "collapsed": false, "input": [ "a_list = []\n", - "print('ID:',id(a_list))\n", + "print(a_list, '\\nID (initial):',id(a_list), '\\n')\n", "\n", "a_list.append(1)\n", - "print('ID (append):',id(a_list))\n", + "print(a_list, '\\nID (append):',id(a_list), '\\n')\n", "\n", - "a_list.append(2)\n", - "print('ID (extend):',id(a_list))" + "a_list.extend([2])\n", + "print(a_list, '\\nID (extend):',id(a_list))" ], "language": "python", "metadata": {}, @@ -289,13 +290,18 @@ "output_type": "stream", "stream": "stdout", "text": [ - "ID: 4366495544\n", - "ID (append): 4366495544\n", - "ID (extend): 4366495544\n" + "[] \n", + "ID (initial): 140704077653128 \n", + "\n", + "[1] \n", + "ID (append): 140704077653128 \n", + "\n", + "[1, 2] \n", + "ID (extend): 140704077653128\n" ] } ], - "prompt_number": 7 + "prompt_number": 6 }, { "cell_type": "code", @@ -2979,6 +2985,102 @@ ], "prompt_number": 4 }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Only the first clause of generators is evaluated immediately" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The main reason why we love to use generators in certain cases (i.e., when we are dealing with large numbers of computations) is that it only computes the next value when it is needed, which is also known as \"lazy\" evaluation.\n", + "However, the first clause of an generator is already checked upon it's creation, as the following example demonstrates:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "gen_fails = (i for i in 1/0)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "ename": "ZeroDivisionError", + "evalue": "division by zero", + "output_type": "pyerr", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mgen_fails\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero" + ] + } + ], + "prompt_number": 18 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Certainly, this is a nice feature, since it notifies us about syntax erros immediately. However, this is (unfortunately) not the case if we have multiple cases in our generator." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "gen_succeeds = (i for i in range(5) for j in 1/0)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 19 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print('But obviously fails when we iterate ...')\n", + "for i in gen_succeeds:\n", + " print(i)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "ename": "ZeroDivisionError", + "evalue": "division by zero", + "output_type": "pyerr", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mZeroDivisionError\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[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'But obviously fails when we iterate ...'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mgen_succeeds\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m(.0)\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mgen_succeeds\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero" + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "But obviously fails when we iterate ...\n" + ] + } + ], + "prompt_number": 20 + }, { "cell_type": "markdown", "metadata": {}, @@ -3009,19 +3111,10 @@ "metadata": {}, "source": [ "#### 04/27/2014\n", - "- minor fixes of typos\n", - "- single- vs. double-underscore clarification in the private class section." + "- minor fixes of typos \n", + "- new section: \"Only the first clause of generators is evaluated immediately\"" ] }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [], - "prompt_number": 1 - }, { "cell_type": "code", "collapsed": false, From bef5bc03a94297bb59e5ef5ff00d1abfe9a73038 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Mon, 28 Apr 2014 21:42:13 -0400 Subject: [PATCH 02/26] legb scope tutorial --- tutorials/scope_resolution_legb_rule.ipynb | 644 +++++++++++++++++++++ 1 file changed, 644 insertions(+) create mode 100644 tutorials/scope_resolution_legb_rule.ipynb diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb new file mode 100644 index 0000000..f687fbf --- /dev/null +++ b/tutorials/scope_resolution_legb_rule.ipynb @@ -0,0 +1,644 @@ +{ + "metadata": { + "name": "scope_resolution_legb_rule" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[Sebastian Raschka](http://www.sebastianraschka.com) \n", + "last updated: 04/28/2014\n", + "\n", + "- [Link to the containing GitHub Repository](https://github.com/rasbt/python_reference)\n", + "- [Link to this IPython Notebook on GitHub](https://github.com/rasbt/pattern_classification/blob/master/python_reference/tutorials/scope_legb_rule.ipynb)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "I am really looking forward to your comments and suggestions to improve and extend this tutorial! Just send me a quick note \n", + "via Twitter: [@rasbt](https://twitter.com/rasbt) \n", + "or Email: [bluewoodtree@gmail.com](mailto:bluewoodtree@gmail.com)\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#Python's scope resolution for variable names and the LEGB rule" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is a short tutorial about Python's scope resolution for variable names using the LEGB-rule. The following section will have short example code blocks that should illustrate the problem followed by short explanations. You can simply read it from start to end, but I'd recommend you to execute the code snippets yourself by copy & paste, or by directly [downloading this IPython notebook](https://github.com/rasbt/python_reference/raw/master/python_true_false.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sections\n", + "- [Introduction to namespaces and scopes](#introduction) \n", + "- [1. LG - Local vs. Global](section_1) \n", + "- [2. LEG - Local, Enclosed, and Global scope](section_2) \n", + "- [3. LEGB - Local, Enclosed, Global, Built-in](section_3) \n", + "- [Conclusion](conclusion) \n", + "- [Solutions](#solutions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Objectives\n", + "- Namespaces and scopes - Where does Python look for variable names?\n", + "- What happens if the same variable name is defined (reused) multiple times?\n", + "- In which order are namespaces being searched for variable names?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction to namespaces and scopes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A namespace represents a mapping from names to objects. E.g., if we want to access any Python object, we do it by the associated name. \n", + "We could picture a namespace as a simple dicitonary, e.g., \n", + "`a_namespace = {'name_a':object_a, 'name_b':object_b, ...}` \n", + "(which is also how namespaces are currently implemented in Python). \n", + "\n", + "Multiple namespaces can use the same names independent from each other. \n", + "In Python, we have separate namespaces for e.g., built-in variables, global variables, different classes, modules, functions, etc. \n", + "A simple example could be: \n", + "\n", + "`global_namespace = {'name_a':object_1, 'name_b':object_2, ...}`, \n", + "`namespace_of_function_b = {'name_a':object_3, 'name_b':object_4, ...}`\n", + "\n", + "For example, let's assume we want to access an object via its name `name_a`, in which namespace would Python look up the mapping?\n", + "\n", + "This is where the concept of **scope** comes into play. In Python, we have 4 different scopes: **L** ocal, **E** nclosed, **G** lobal, **B** uilt-in (LEGB). \n", + "According to the LEGB-rule, Python looks for an object through the namespaces in the following order L -> E -> G -> B: If a variable name is not found in the local namespaces, the namespaces of the enclosed scope are being searched, and if the variable name is also not defined here, the global namespaces come next and so forth." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "###1. LG - Local vs. Global" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Example 1.1** \n", + "As a warm-up exercise, let us first forget about the enclosed (E) and built-in (B) scopes in the LEGB rule and take a look at LG - the local and global scope. \n", + "What does the following code print?" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "a_var = 'global variable'\n", + "\n", + "def a_func():\n", + " print(a_var, '[ a_var inside a_func() ]')\n", + "\n", + "#a_func()\n", + "#print(a_var, '[ a_var outside a_func() ]')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 1 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**a)**\n", + "
raises an error
\n", + "\n", + "**b)** \n", + "
\n",
+      "global value [ a_var outside a_func() ]
\n", + "\n", + "**c)** \n", + "
global value [ a_var in a_func() ]  \n",
+      "global value [ a_var outside a_func() ]
\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[go to solution](#solutions)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Here is why:\n", + "\n", + "We call `a_func()` first, which is supposed to print the value of `a_var`. According to the LEGB rule, the function will first look in its own local scope (L) if `a_var` is defined there. Since `a_func()` does not have its own `a_var`, it will look one-level above in the global scope (G) in which we defined `a_var` previously.\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Example 1.2** \n", + "Now, let us define the variable `a_var` in the global and the local scope. \n", + "Can you guess what the following code will produce?" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "a_var = 'global value'\n", + "\n", + "def a_func():\n", + " a_var = 'local value'\n", + " print(a_var, '[ a_var inside a_func() ]')\n", + "\n", + "#a_func()\n", + "#print(a_var, '[ a_var outside a_func() ]')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 2 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**a)**\n", + "
raises an error
\n", + "\n", + "**b)** \n", + "
local value [ a_var in a_func() ]\n",
+      "global value [ a_var outside a_func() ]
\n", + "\n", + "**c)** \n", + "
global value [ a_var in a_func() ]  \n",
+      "global value [ a_var outside a_func() ]
\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[go to solution](#solutions)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Here is why:\n", + "\n", + "When we call `a_func()`, it will first look in its local scope (L) for `a_var`, since `a_var` is defined in the local scope of `a_func`, its assigned value `local variable` is printed. Note that this doesn't affect the global variable, which is in a different scope." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "However, it is also possible to modify the global by, e.g., re-assigning a new value to it if we use the global keyword as the following example will illustrate:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "a_var = 'global value'\n", + "\n", + "def a_func():\n", + " global a_var\n", + " a_var = 'local value'\n", + " print(a_var, '[ a_var inside a_func() ]')\n", + "\n", + "#print(a_var, '[ a_var outside a_func() ]')\n", + "#a_func()\n", + "#print(a_var, '[ a_var outside a_func() ]')" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 3 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But we have to be careful about the order: it is easy to raise an `UnboundLocalError` if we don't explicitly tell Python that we want to use the global scope and try to modify a variable's value (remember, the right side of an assignment operation is executed first):" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "a_var = 1\n", + "\n", + "def a_func():\n", + " a_var = a_var + 1\n", + " print(a_var, '[ a_var inside a_func() ]')\n", + "\n", + "print(a_var, '[ a_var outside a_func() ]')\n", + "a_func()" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "ename": "UnboundLocalError", + "evalue": "local variable 'a_var' referenced before assignment", + "output_type": "pyerr", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mUnboundLocalError\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 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma_var\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'[ a_var outside a_func() ]'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0ma_func\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36ma_func\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0ma_func\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0ma_var\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma_var\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'[ a_var inside a_func() ]'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'a_var' referenced before assignment" + ] + }, + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "1 [ a_var outside a_func() ]\n" + ] + } + ], + "prompt_number": 29 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. LEG - Local, Enclosed, and Global scope\n", + "\n", + "\n", + "\n", + "Now, let us introduce the concept of the enclosed (E) scope. Following the order \"Local -> Enclosed -> Global\", can you guess what the following code will print?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Example 2.1**" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "a_var = 'global value'\n", + "\n", + "def outer():\n", + " a_var = 'enclosed value'\n", + " \n", + " def inner():\n", + " a_var = 'local value'\n", + " print(a_var)\n", + " \n", + " inner()\n", + "\n", + "#outer()" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**a)**\n", + "
global value
\n", + "\n", + "**b)** \n", + "
enclosed value
\n", + "\n", + "**c)** \n", + "
local value
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[go to solution](#solutions)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Here is why:\n", + "\n", + "Let us quickly recapitulate what we just did: We called `outer()`, which defines the variable `a_var` locally (next to an existing `a_var` in the global scope). The `outer()` function then calls `inner()`, which in turn defines a variable with the name `a_var` as well. The `print()` function inside `inner()` looks in the local scope first (L->E), before it goes up the scope hierarchy, and therefore prints the value that was assigned in the local scope." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similar to the concept of the `global` keyword, which we have seen in the section above, we can use the keyword `nonlocal` inside the inner function to explicitely access a variable from the outer (enclosed) scope in order to modify its value:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "a_var = 'global value'\n", + "\n", + "def outer():\n", + " a_var = 'local value'\n", + " print('outer before:', a_var)\n", + " def inner():\n", + " nonlocal a_var\n", + " a_var = 'inner value'\n", + " print('in inner():', a_var)\n", + " inner()\n", + " print(\"outer after:\", a_var)\n", + "#outer()" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 5 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. LEGB - Local, Enclosed, Global, Built-in\n", + "\n", + "To wrap up the LEGB rule, let us come to the built-in scope. Here, we will define our \"own\" length-funcion, which happens to bear the same name as the in-built `len()` function. What outcome do you excpect if we'd execute the following code?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Example 3**" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "a_var = 'global variable'\n", + "\n", + "\n", + "\n", + "def len(in_var):\n", + " print('called my len() function')\n", + " l = 0\n", + " for i in in_var:\n", + " l += 1\n", + " return l\n", + "\n", + "def a_func(in_var):\n", + " len_in_var = len(in_var)\n", + " print('Input variable is of length', len_in_var)\n", + "\n", + "#a_func('Hello, World!')\n", + " " + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 85 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**a)**\n", + "
raises an error (conflict with in-built `len()` function)
\n", + "\n", + "**b)** \n", + "
called my len() function\n",
+      "Input variable is of length 13
\n", + "\n", + "**c)** \n", + "
Input variable is of length 13
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[go to solution](#solutions)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Here is why:\n", + "\n", + "Since the exact same names can be used to map names to different objects - as long as the names are in different name spaces - there is no problem of reusing the name `len` to define our own length function (this is just for demonstration pruposes, it is NOT recommended). As we go up in Python's L -> E -> G -> B hierarchy, the function `a_func()` finds `len()` in the global scope first, before it attempts to search the namespaces in the built-in scope." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclusion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "I hope this short tutorial was helpful to understand the basic concept of Python's scope resolution order using the LEGB rule. I want to encourage you (as a little self-assessment exercise) to look at the code snippets again tomorrow and check if you can correctly predict all their outcomes." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### A rule of thumb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In practice, **it is usually a bad idea to modify global variables inside the function scope**, since it often be the cause of confusion and weird errors that are hard to debug. \n", + "If you want to modify a global variable via a function, it is recommended to pass it as an argument and reassign the return-value. \n", + "For example:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "a_var = 2\n", + "\n", + "def a_func(some_var):\n", + " return 2**3\n", + "\n", + "a_var = a_func(a_var)\n", + "print(a_var)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "8\n" + ] + } + ], + "prompt_number": 42 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Solutions\n", + "\n", + "In order to prevent you from unintentional spoilers, I have written the solutions in binary format. In order to display the character representation, you just need to execute the following lines of code:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print('Example 1.1:', chr(int('01100011',2)))" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 6 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print('Example 1.2:', chr(int('01100001',2)))" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 7 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print('Example 2.1:', chr(int('01100011',2)))" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 8 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print('Example 3.1:', chr(int('01100010',2)))" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 9 + } + ], + "metadata": {} + } + ] +} \ No newline at end of file From f290e49f00796df419e1cce2cbf20c217ef406e0 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Mon, 28 Apr 2014 21:46:05 -0400 Subject: [PATCH 03/26] legb scope tutorial --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cc1f5ea..c983c1b 100755 --- a/README.md +++ b/README.md @@ -9,4 +9,5 @@ Syntax examples for useful Python functions, methods, and modules - [Python benchmarks via `timeit`](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/benchmarks/timeit_tests.ipynb?create=1) - [Benchmarks of different palindrome functions](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/benchmarks/palindrome_timeit.ipynb?create=1) - [A collection of not so obvious Python stuff you should know!](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/not_so_obvious_python_stuff.ipynb?create=1) +- [Python's scope resolution for variable names and the LEGB rule](https://github.com/rasbt/python_reference/blob/master/tutorials/scope_resolution_legb_rule.ipynb) From c4f0cc8bea5e3e208846d4ed7aa8541819fb2e57 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Mon, 28 Apr 2014 21:48:02 -0400 Subject: [PATCH 04/26] legb scope tutorial --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c983c1b..19adc90 100755 --- a/README.md +++ b/README.md @@ -9,5 +9,5 @@ Syntax examples for useful Python functions, methods, and modules - [Python benchmarks via `timeit`](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/benchmarks/timeit_tests.ipynb?create=1) - [Benchmarks of different palindrome functions](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/benchmarks/palindrome_timeit.ipynb?create=1) - [A collection of not so obvious Python stuff you should know!](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/not_so_obvious_python_stuff.ipynb?create=1) -- [Python's scope resolution for variable names and the LEGB rule](https://github.com/rasbt/python_reference/blob/master/tutorials/scope_resolution_legb_rule.ipynb) +- [Python's scope resolution for variable names and the LEGB rule](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/tutorials/scope_resolution_legb_rule.ipynb?create=1) From 19ae86ab1aa94bfeb294e1dd78148baa4964bc00 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Mon, 28 Apr 2014 21:50:35 -0400 Subject: [PATCH 05/26] legb scope tutorial --- tutorials/scope_resolution_legb_rule.ipynb | 29 ++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb index f687fbf..1b0d2a3 100644 --- a/tutorials/scope_resolution_legb_rule.ipynb +++ b/tutorials/scope_resolution_legb_rule.ipynb @@ -41,7 +41,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This is a short tutorial about Python's scope resolution for variable names using the LEGB-rule. The following section will have short example code blocks that should illustrate the problem followed by short explanations. You can simply read it from start to end, but I'd recommend you to execute the code snippets yourself by copy & paste, or by directly [downloading this IPython notebook](https://github.com/rasbt/python_reference/raw/master/python_true_false.ipynb)." + "This is a short tutorial about Python's scope resolution for variable names using the LEGB-rule. The following section will have short example code blocks that should illustrate the problem followed by short explanations. You can simply read it from start to end, but I'd recommend you to execute the code snippets yourself by copy & paste, or by directly [downloading this IPython notebook](https://github.com/rasbt/python_reference/tutorials/raw/master/scope_resolution.ipynb)." ] }, { @@ -59,10 +59,10 @@ "source": [ "## Sections\n", "- [Introduction to namespaces and scopes](#introduction) \n", - "- [1. LG - Local vs. Global](section_1) \n", - "- [2. LEG - Local, Enclosed, and Global scope](section_2) \n", - "- [3. LEGB - Local, Enclosed, Global, Built-in](section_3) \n", - "- [Conclusion](conclusion) \n", + "- [1. LG - Local vs. Global](#section_1) \n", + "- [2. LEG - Local, Enclosed, and Global scope](#section_2) \n", + "- [3. LEGB - Local, Enclosed, Global, Built-in](#section_3) \n", + "- [Conclusion](#conclusion) \n", "- [Solutions](#solutions)" ] }, @@ -122,6 +122,15 @@ "According to the LEGB-rule, Python looks for an object through the namespaces in the following order L -> E -> G -> B: If a variable name is not found in the local namespaces, the namespaces of the enclosed scope are being searched, and if the variable name is also not defined here, the global namespaces come next and so forth." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "
" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -330,6 +339,15 @@ "
" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + "
" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -433,6 +451,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\n", "
\n", "
" ] From a6777f450d13e1f26fd5a17e6d9ba7600fbd912b Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Mon, 28 Apr 2014 21:52:46 -0400 Subject: [PATCH 06/26] legb scope tutorial --- tutorials/scope_resolution_legb_rule.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb index 1b0d2a3..6e5c93d 100644 --- a/tutorials/scope_resolution_legb_rule.ipynb +++ b/tutorials/scope_resolution_legb_rule.ipynb @@ -41,7 +41,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This is a short tutorial about Python's scope resolution for variable names using the LEGB-rule. The following section will have short example code blocks that should illustrate the problem followed by short explanations. You can simply read it from start to end, but I'd recommend you to execute the code snippets yourself by copy & paste, or by directly [downloading this IPython notebook](https://github.com/rasbt/python_reference/tutorials/raw/master/scope_resolution.ipynb)." + "This is a short tutorial about Python's scope resolution for variable names using the LEGB-rule. The following section will have short example code blocks that should illustrate the problem followed by short explanations. You can simply read it from start to end, but I'd recommend you to execute the code snippets yourself by copy & paste, or by directly [downloading this IPython notebook](https://raw.githubusercontent.com/rasbt/python_reference/master/tutorials/scope_resolution_legb_rule.ipynb)." ] }, { From 1351a0043694dcd4f4adac218e1c8d96462bd850 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Tue, 29 Apr 2014 00:10:26 -0400 Subject: [PATCH 07/26] some typo fixes --- tutorials/scope_resolution_legb_rule.ipynb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb index 6e5c93d..d17a5d3 100644 --- a/tutorials/scope_resolution_legb_rule.ipynb +++ b/tutorials/scope_resolution_legb_rule.ipynb @@ -41,7 +41,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This is a short tutorial about Python's scope resolution for variable names using the LEGB-rule. The following section will have short example code blocks that should illustrate the problem followed by short explanations. You can simply read it from start to end, but I'd recommend you to execute the code snippets yourself by copy & paste, or by directly [downloading this IPython notebook](https://raw.githubusercontent.com/rasbt/python_reference/master/tutorials/scope_resolution_legb_rule.ipynb)." + "This is a short tutorial about Python's scope resolution for variable names using the LEGB-rule. The following section will provide short example code blocks that should illustrate the problem followed by short explanations. You can simply read this tutorial from start to end, but I'd like to ecourage you to execute the code snippets - you can either copy & paste them, or for your convenience, simply [download this IPython notebook](https://raw.githubusercontent.com/rasbt/python_reference/master/tutorials/scope_resolution_legb_rule.ipynb)." ] }, { @@ -79,9 +79,9 @@ "metadata": {}, "source": [ "## Objectives\n", - "- Namespaces and scopes - Where does Python look for variable names?\n", - "- What happens if the same variable name is defined (reused) multiple times?\n", - "- In which order are namespaces being searched for variable names?" + "- Namespaces and scopes - where does Python look for variable names?\n", + "- Can we define/reuse variable names for multiple objects at the same time?\n", + "- In which order does Python search different namespaces for variable names?" ] }, { @@ -104,7 +104,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "A namespace represents a mapping from names to objects. E.g., if we want to access any Python object, we do it by the associated name. \n", + "A namespace represents a mapping from names to objects, and we can access any object in Python by its associated name. E.g., if we create a list object `a_list = [1, 2, 3]`, we can modify this list by using its variable name `a_list`, which maps to the list object stored in the memory.\n", "We could picture a namespace as a simple dicitonary, e.g., \n", "`a_namespace = {'name_a':object_a, 'name_b':object_b, ...}` \n", "(which is also how namespaces are currently implemented in Python). \n", @@ -119,7 +119,7 @@ "For example, let's assume we want to access an object via its name `name_a`, in which namespace would Python look up the mapping?\n", "\n", "This is where the concept of **scope** comes into play. In Python, we have 4 different scopes: **L** ocal, **E** nclosed, **G** lobal, **B** uilt-in (LEGB). \n", - "According to the LEGB-rule, Python looks for an object through the namespaces in the following order L -> E -> G -> B: If a variable name is not found in the local namespaces, the namespaces of the enclosed scope are being searched, and if the variable name is also not defined here, the global namespaces come next and so forth." + "According to the LEGB-rule, Python searches the different namespace levels in the following order L -> E -> G -> B, i.e., if a particular name:object mapping cannot be found in the local namespaces, the namespaces of the enclosed scope are being searched next. If the search in the enclosed scope is unsuccessful, too, Python moves on to the global namespace, and eventually, it will search the global namespaces (side note: if a name cannot found in any of the namespaces, a `NameError` is raised)." ] }, { @@ -143,7 +143,7 @@ "metadata": {}, "source": [ "**Example 1.1** \n", - "As a warm-up exercise, let us first forget about the enclosed (E) and built-in (B) scopes in the LEGB rule and take a look at LG - the local and global scope. \n", + "As a warm-up exercise, let us first forget about the enclosed (E) and built-in (B) scopes in the LEGB rule and only take a look at LG - the local and global scopes. \n", "What does the following code print?" ] }, @@ -195,7 +195,7 @@ "source": [ "### Here is why:\n", "\n", - "We call `a_func()` first, which is supposed to print the value of `a_var`. According to the LEGB rule, the function will first look in its own local scope (L) if `a_var` is defined there. Since `a_func()` does not have its own `a_var`, it will look one-level above in the global scope (G) in which we defined `a_var` previously.\n", + "We call `a_func()` first, which is supposed to print the value of `a_var`. According to the LEGB rule, the function will first look in its own local scope (L) if `a_var` is defined there. Since `a_func()` does not define its own `a_var`, it will look one-level above in the global scope (G) in which `a_var` has been defined previously.\n", "
\n", "
" ] @@ -415,7 +415,7 @@ "source": [ "### Here is why:\n", "\n", - "Let us quickly recapitulate what we just did: We called `outer()`, which defines the variable `a_var` locally (next to an existing `a_var` in the global scope). The `outer()` function then calls `inner()`, which in turn defines a variable with the name `a_var` as well. The `print()` function inside `inner()` looks in the local scope first (L->E), before it goes up the scope hierarchy, and therefore prints the value that was assigned in the local scope." + "Let us quickly recapitulate what we just did: We called `outer()`, which defined the variable `a_var` locally (next to an existing `a_var` in the global scope). Next, the `outer()` function called `inner()`, which in turn defined a variable with of name `a_var` as well. The `print()` function inside `inner()` searched in the local scope first (L->E) before it went up in the scope hierarchy, and therefore it printed the value that was assigned in the local scope." ] }, { @@ -527,7 +527,7 @@ "source": [ "### Here is why:\n", "\n", - "Since the exact same names can be used to map names to different objects - as long as the names are in different name spaces - there is no problem of reusing the name `len` to define our own length function (this is just for demonstration pruposes, it is NOT recommended). As we go up in Python's L -> E -> G -> B hierarchy, the function `a_func()` finds `len()` in the global scope first, before it attempts to search the namespaces in the built-in scope." + "Since the exact same names can be used to map names to different objects - as long as the names are in different name spaces - there is no problem of reusing the name `len` to define our own length function (this is just for demonstration pruposes, it is NOT recommended). As we go up in Python's L -> E -> G -> B hierarchy, the function `a_func()` finds `len()` already in the global scope first before it attempts" ] }, { From 36b1d10372acdee31afbbe339c917eb8550ca470 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Tue, 29 Apr 2014 01:21:34 -0400 Subject: [PATCH 08/26] small fixes --- tutorials/scope_resolution_legb_rule.ipynb | 40 ++++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb index d17a5d3..cc618ff 100644 --- a/tutorials/scope_resolution_legb_rule.ipynb +++ b/tutorials/scope_resolution_legb_rule.ipynb @@ -278,13 +278,23 @@ " a_var = 'local value'\n", " print(a_var, '[ a_var inside a_func() ]')\n", "\n", - "#print(a_var, '[ a_var outside a_func() ]')\n", - "#a_func()\n", - "#print(a_var, '[ a_var outside a_func() ]')" + "print(a_var, '[ a_var outside a_func() ]')\n", + "a_func()\n", + "print(a_var, '[ a_var outside a_func() ]')" ], "language": "python", "metadata": {}, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "global value [ a_var outside a_func() ]\n", + "local value [ a_var inside a_func() ]\n", + "local value [ a_var outside a_func() ]\n" + ] + } + ], "prompt_number": 3 }, { @@ -316,8 +326,8 @@ "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mUnboundLocalError\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 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma_var\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'[ a_var outside a_func() ]'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0ma_func\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36ma_func\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0ma_func\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0ma_var\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma_var\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'[ a_var inside a_func() ]'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma_var\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'[ a_var outside a_func() ]'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0ma_func\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36ma_func\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0ma_func\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0ma_var\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0ma_var\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma_var\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'[ a_var inside a_func() ]'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'a_var' referenced before assignment" ] }, @@ -329,7 +339,7 @@ ] } ], - "prompt_number": 29 + "prompt_number": 4 }, { "cell_type": "markdown", @@ -440,11 +450,21 @@ " print('in inner():', a_var)\n", " inner()\n", " print(\"outer after:\", a_var)\n", - "#outer()" + "outer()" ], "language": "python", "metadata": {}, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "outer before: local value\n", + "in inner(): inner value\n", + "outer after: inner value\n" + ] + } + ], "prompt_number": 5 }, { @@ -497,7 +517,7 @@ "language": "python", "metadata": {}, "outputs": [], - "prompt_number": 85 + "prompt_number": 6 }, { "cell_type": "markdown", From ccb3947fde8daaba198b30d43e2db0c5f2104092 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Tue, 29 Apr 2014 01:25:52 -0400 Subject: [PATCH 09/26] small fixes --- tutorials/scope_resolution_legb_rule.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb index cc618ff..c97a1e4 100644 --- a/tutorials/scope_resolution_legb_rule.ipynb +++ b/tutorials/scope_resolution_legb_rule.ipynb @@ -15,7 +15,7 @@ "last updated: 04/28/2014\n", "\n", "- [Link to the containing GitHub Repository](https://github.com/rasbt/python_reference)\n", - "- [Link to this IPython Notebook on GitHub](https://github.com/rasbt/pattern_classification/blob/master/python_reference/tutorials/scope_legb_rule.ipynb)\n", + "- [Link to this IPython Notebook on GitHub](https://github.com/rasbt/python_reference/blob/master/tutorials/scope_resolution_legb_rule.ipynb)\n", "\n" ] }, From 4dac403cdc97f8976d53fc1d4e1c5dd6304a7afe Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Tue, 29 Apr 2014 09:53:17 -0400 Subject: [PATCH 10/26] self assessment --- tutorials/scope_resolution_legb_rule.ipynb | 99 +++++++++++++++++++++- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb index c97a1e4..d1370e4 100644 --- a/tutorials/scope_resolution_legb_rule.ipynb +++ b/tutorials/scope_resolution_legb_rule.ipynb @@ -62,6 +62,7 @@ "- [1. LG - Local vs. Global](#section_1) \n", "- [2. LEG - Local, Enclosed, and Global scope](#section_2) \n", "- [3. LEGB - Local, Enclosed, Global, Built-in](#section_3) \n", + "- [Self-assessment exercise](#assessment)\n", "- [Conclusion](#conclusion) \n", "- [Solutions](#solutions)" ] @@ -498,8 +499,6 @@ "input": [ "a_var = 'global variable'\n", "\n", - "\n", - "\n", "def len(in_var):\n", " print('called my len() function')\n", " l = 0\n", @@ -511,8 +510,7 @@ " len_in_var = len(in_var)\n", " print('Input variable is of length', len_in_var)\n", "\n", - "#a_func('Hello, World!')\n", - " " + "#a_func('Hello, World!')" ], "language": "python", "metadata": {}, @@ -550,6 +548,65 @@ "Since the exact same names can be used to map names to different objects - as long as the names are in different name spaces - there is no problem of reusing the name `len` to define our own length function (this is just for demonstration pruposes, it is NOT recommended). As we go up in Python's L -> E -> G -> B hierarchy, the function `a_func()` finds `len()` already in the global scope first before it attempts" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Self-assessment exercise" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, after we went through a couple of exercises, let us quickly check where we are. So, one more time: What would the following code print out?" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "a = 'global'\n", + "\n", + "def outer():\n", + " \n", + " def len(in_var):\n", + " print('called my len() function: ', end=\"\")\n", + " l = 0\n", + " for i in in_var:\n", + " l += 1\n", + " return l\n", + " \n", + " a = 'local'\n", + " \n", + " def inner():\n", + " global len\n", + " nonlocal a\n", + " a += ' variable'\n", + " inner()\n", + " print('a is', a)\n", + " print(len(a))\n", + "\n", + "\n", + "outer()\n", + "\n", + "print(len(a))\n", + "print('a is', a)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 59 + }, { "cell_type": "markdown", "metadata": {}, @@ -559,6 +616,13 @@ "
" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[go to solution](#solutions)]" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -675,6 +739,33 @@ "metadata": {}, "outputs": [], "prompt_number": 9 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# Execute to run the self-assessment solution\n", + "\n", + "sol = \"000010100110111101110101011101000110010101110010001010\"\\\n", + "\"0000101001001110100000101000001010011000010010000001101001011100110\"\\\n", + "\"0100000011011000110111101100011011000010110110000100000011101100110\"\\\n", + "\"0001011100100110100101100001011000100110110001100101000010100110001\"\\\n", + "\"1011000010110110001101100011001010110010000100000011011010111100100\"\\\n", + "\"1000000110110001100101011011100010100000101001001000000110011001110\"\\\n", + "\"1010110111001100011011101000110100101101111011011100011101000100000\"\\\n", + "\"0011000100110100000010100000101001100111011011000110111101100010011\"\\\n", + "\"0000101101100001110100000101000001010001101100000101001100001001000\"\\\n", + "\"0001101001011100110010000001100111011011000110111101100010011000010\"\\\n", + "\"1101100\"\n", + "\n", + "sol_str =''.join(chr(int(sol[i:i+8], 2)) for i in range(0, len(sol), 8))\n", + "for line in sol_str.split('\\n'):\n", + " print(line)" + ], + "language": "python", + "metadata": {}, + "outputs": [], + "prompt_number": 58 } ], "metadata": {} From 7290f5c862517f700993f211e4761b07887df88b Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Tue, 29 Apr 2014 20:06:40 -0400 Subject: [PATCH 11/26] legb update --- tutorials/scope_resolution_legb_rule.ipynb | 313 +++++++++++++++++++-- 1 file changed, 291 insertions(+), 22 deletions(-) diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb index d1370e4..1562be6 100644 --- a/tutorials/scope_resolution_legb_rule.ipynb +++ b/tutorials/scope_resolution_legb_rule.ipynb @@ -34,14 +34,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#Python's scope resolution for variable names and the LEGB rule" + "#A beginner's guide to Python's namespaces, scope resolution, and the LEGB rule" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This is a short tutorial about Python's scope resolution for variable names using the LEGB-rule. The following section will provide short example code blocks that should illustrate the problem followed by short explanations. You can simply read this tutorial from start to end, but I'd like to ecourage you to execute the code snippets - you can either copy & paste them, or for your convenience, simply [download this IPython notebook](https://raw.githubusercontent.com/rasbt/python_reference/master/tutorials/scope_resolution_legb_rule.ipynb)." + "This is a short tutorial about Python's namespaces and the scope resolution for variable names using the LEGB-rule. The following sections will provide short example code blocks that should illustrate the problem followed by short explanations. You can simply read this tutorial from start to end, but I'd like to encourage you to execute the code snippets - you can either copy & paste them, or for your convenience, simply [download this IPython notebook](https://raw.githubusercontent.com/rasbt/python_reference/master/tutorials/scope_resolution_legb_rule.ipynb)." ] }, { @@ -64,7 +64,8 @@ "- [3. LEGB - Local, Enclosed, Global, Built-in](#section_3) \n", "- [Self-assessment exercise](#assessment)\n", "- [Conclusion](#conclusion) \n", - "- [Solutions](#solutions)" + "- [Solutions](#solutions)\n", + "- [Warning: For-loop variables cutting into the global namespace](#for_loop)" ] }, { @@ -105,22 +106,161 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "A namespace represents a mapping from names to objects, and we can access any object in Python by its associated name. E.g., if we create a list object `a_list = [1, 2, 3]`, we can modify this list by using its variable name `a_list`, which maps to the list object stored in the memory.\n", - "We could picture a namespace as a simple dicitonary, e.g., \n", - "`a_namespace = {'name_a':object_a, 'name_b':object_b, ...}` \n", - "(which is also how namespaces are currently implemented in Python). \n", + "### Namespaces" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Roughly speaking, namespaces are just containers for mapping names to objects. As you might have already heard, everything in Python - literals, lists, dictionaries, functions, classes, etc. - is an object. \n", + "Such a \"name-to-object\" mapping allows us to access an object by a name that we've assigned to it. E.g., if we make a simple string assignment via `a_string = \"Hello string\"`, we created a reference to the `\"Hello string\"` object, and henceforth we can access via its variable name `a_string`.\n", "\n", - "Multiple namespaces can use the same names independent from each other. \n", - "In Python, we have separate namespaces for e.g., built-in variables, global variables, different classes, modules, functions, etc. \n", - "A simple example could be: \n", + "We can picture a namespace as a Python dictionary structure, where the dictionary keys represent the names and the dictionary values the object itself (and this is also how namespaces are currently implemented in Python), e.g., \n", "\n", - "`global_namespace = {'name_a':object_1, 'name_b':object_2, ...}`, \n", - "`namespace_of_function_b = {'name_a':object_3, 'name_b':object_4, ...}`\n", + "
a_namespace = {'name_a':object_1, 'name_b':object_2, ...}
\n", "\n", - "For example, let's assume we want to access an object via its name `name_a`, in which namespace would Python look up the mapping?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, the tricky part is that we have multiple independent namespaces in Python, and names can be reused for different namespaces (only the objects are unique, for example:\n", "\n", - "This is where the concept of **scope** comes into play. In Python, we have 4 different scopes: **L** ocal, **E** nclosed, **G** lobal, **B** uilt-in (LEGB). \n", - "According to the LEGB-rule, Python searches the different namespace levels in the following order L -> E -> G -> B, i.e., if a particular name:object mapping cannot be found in the local namespaces, the namespaces of the enclosed scope are being searched next. If the search in the enclosed scope is unsuccessful, too, Python moves on to the global namespace, and eventually, it will search the global namespaces (side note: if a name cannot found in any of the namespaces, a `NameError` is raised)." + "
a_namespace = {'name_a':object_1, 'name_b':object_2, ...}\n",
+      "b_namespace = {'name_a':object_3, 'name_b':object_4, ...}
\n", + "\n", + "For example, everytime we call a `for-loop` or define a function, it will create its own namespace. Namespaces also have different levels of hierarchy (the so-called \"scope\"), which we will discuss in more detail in the next section." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scope" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the section above, we have learned that namespaces can exist independently from each other and that they are structured in a certain hierarchy, which brings us to the concept of \"scope\". The \"scope\" in Python defines the \"hierarchy level\" in which we search namespaces for certain \"name-to-object\" mappings. \n", + "For example, let us consider the following code:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "i = 1\n", + "\n", + "def foo():\n", + " i = 5\n", + " print(i, 'in foo()')\n", + "\n", + "print(i, 'global')\n", + "\n", + "foo()" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "1 global\n", + "5 in foo()\n" + ] + } + ], + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we just defined the variable name `i` twice, once on the `foo` function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `foo_namespace = {'i':object_3, ...}` \n", + "- `global_namespace = {'i':object_1, 'name_b':object_2, ...}`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So, how does Python now which namespace it has to search if we want to print the value of the variable `i`? This is where Python's LEGB-rule comes into play, which we will discuss in the next section." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scope resolution for variable names via the LEGB rule." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have seen that multiple namespaces can exist independently from each other and that they can contain the same variable names on different hierachy levels. The \"scope\" defines on which hierarchy level Python searches for a particular \"variable name\" for its associated object. Now, the next question is: \"In which order does Python search the different levels of namespaces before it finds the name-to-object' mapping?\" \n", + "To answer is: It uses the LEGB-rule, which stands for\n", + "\n", + "**Local -> Enclosed -> Global -> Built-in**, \n", + "\n", + "where the arrows should denote the direction of the namespace-hierarchy search order. \n", + "\n", + "- *Local* can be inside a function or class method, for example. \n", + "- *Enclosed* can be its `enclosing` function, e.g., if a function is wrapped inside another function. \n", + "- *Global* refers to the uppermost level of the executing script itself, and \n", + "- *Built-in* are special names that Python reserves for itself. \n", + "\n", + "So, if a particular name:object mapping cannot be found in the local namespaces, the namespaces of the enclosed scope are being searched next. If the search in the enclosed scope is unsuccessful, too, Python moves on to the global namespace, and eventually, it will search the global namespaces (side note: if a name cannot found in any of the namespaces, a *NameError* will is raised).\n", + "\n", + "**Note**: \n", + "Namespaces can also be further nested, for example if we import modules, or if we are defining new classes. In those cases we have to use prefixes to access those nested namespaces. Let me illustrate this concept in the following code block:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import numpy\n", + "import math\n", + "import scipy\n", + "\n", + "print(math.pi, 'from the math module')\n", + "print(numpy.pi, 'from the numpy package')\n", + "print(scipy.pi, 'from the scipy package')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "3.141592653589793 from the math module\n", + "3.141592653589793 from the numpy package\n", + "3.141592653589793 from the scipy package\n" + ] + } + ], + "prompt_number": 8 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(This is also why we have to be careful if we import modules via \"`from a_module import *`\", since it loads the variable names into the global namespace and could potentially overwrite already existing variable names)" ] }, { @@ -132,13 +272,6 @@ "
" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "###1. LG - Local vs. Global" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -766,6 +899,142 @@ "metadata": {}, "outputs": [], "prompt_number": 58 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Warning: For-loop variables cutting into the global namespace" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As it was briefly mentioned in the introduction, `for-loops` will create their own namespaces, which will be deleted after the for-loop has completed. Consider the following example (exectuted in Python 3.4):\n" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "for a in range(5):\n", + " if a == 4:\n", + " print(a, '-> a in for-loop')\n", + "print(a, '-> a in global')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "4 -> a in for-loop\n", + "4 -> a in global\n" + ] + } + ], + "prompt_number": 15 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can roughly sketch the situation as follows \n", + "\n", + "*before the for-loop*: \n", + "`- global_namespace = {'a_name':object1, ...}`\n", + "\n", + "*during the for-loop*: \n", + "`- global_namespace = {'a_name':object1, ...}` \n", + "`- for-loop_namespace = {'a':object201, ...}`\n", + "\n", + "*after the for-loop*: \n", + "`- global_namespace = {'a_name':object1, ...}`\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**However, this does not apply if we defined the `for-loop` variable in the global namespace before!**" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "b = 1\n", + "for b in range(5):\n", + " if b == 4:\n", + " print(a, '-> b in for-loop')\n", + "print(b, '-> b in global')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "4 -> b in for-loop\n", + "4 -> b in global\n" + ] + } + ], + "prompt_number": 17 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In **Python 3.4**, we can use closures to prevent the for-loop variable to cut into the global namespace. Here is an example (exectuted in Python 3.4):" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "i = 1\n", + "print([i for i in range(5)])\n", + "print(i, '-> i in global')" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "[0, 1, 2, 3, 4]\n", + "1 -> i in global\n" + ] + } + ], + "prompt_number": 14 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Why did I mention \"Python 3.4\"? Well, as it happens, the same code executed in Python 2.x would print:\n", + "\n", + "
\n",
+      "print(4, '-> i in global')\n",
+      "
"
+     ]
     }
    ],
    "metadata": {}

From 2587ebf9db86614e2e885574d86c2c5875abdf4f Mon Sep 17 00:00:00 2001
From: Sebastian Raschka 
Date: Tue, 29 Apr 2014 20:58:41 -0400
Subject: [PATCH 12/26] typo upd.

---
 tutorials/scope_resolution_legb_rule.ipynb | 35 +++++++++++++++++++---
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb
index 1562be6..009b57e 100644
--- a/tutorials/scope_resolution_legb_rule.ipynb
+++ b/tutorials/scope_resolution_legb_rule.ipynb
@@ -59,7 +59,7 @@
      "source": [
       "## Sections\n",
       "- [Introduction to namespaces and scopes](#introduction)  \n",
-      "- [1. LG - Local vs. Global](#section_1)  \n",
+      "- [1. LG - Local and Global scopes](#section_1)  \n",
       "- [2. LEG - Local, Enclosed, and Global scope](#section_2)  \n",
       "- [3. LEGB - Local, Enclosed, Global, Built-in](#section_3)  \n",
       "- [Self-assessment exercise](#assessment)\n",
@@ -272,6 +272,13 @@
       "
" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. LG - Local and Global scopes" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -483,6 +490,26 @@ "
" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tip:\n", + "If we want to print out the dictionary mapping of the global and local variables, we can use the\n", + "the functions `global()` and `local()" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "print(global()) # prints global namespace\n", + "print(local()) # prints local namespace" + ], + "language": "python", + "metadata": {}, + "outputs": [] + }, { "cell_type": "markdown", "metadata": {}, @@ -979,7 +1006,7 @@ "b = 1\n", "for b in range(5):\n", " if b == 4:\n", - " print(a, '-> b in for-loop')\n", + " print(b, '-> b in for-loop')\n", "print(b, '-> b in global')" ], "language": "python", @@ -994,7 +1021,7 @@ ] } ], - "prompt_number": 17 + "prompt_number": 7 }, { "cell_type": "markdown", @@ -1023,7 +1050,7 @@ ] } ], - "prompt_number": 14 + "prompt_number": 1 }, { "cell_type": "markdown", From c3fc8395e20fc625f9f4554976750a20de17eebf Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Tue, 29 Apr 2014 21:25:40 -0400 Subject: [PATCH 13/26] fixed for-loop example --- tutorials/scope_resolution_legb_rule.ipynb | 39 ++++++++-------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb index 009b57e..2ee602a 100644 --- a/tutorials/scope_resolution_legb_rule.ipynb +++ b/tutorials/scope_resolution_legb_rule.ipynb @@ -947,7 +947,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As it was briefly mentioned in the introduction, `for-loops` will create their own namespaces, which will be deleted after the for-loop has completed. Consider the following example (exectuted in Python 3.4):\n" + "In contrast to some other programming languages, `for-loops` will use the scope they exist in and leave their defined loop-variable behind.\n" ] }, { @@ -971,32 +971,13 @@ ] } ], - "prompt_number": 15 + "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We can roughly sketch the situation as follows \n", - "\n", - "*before the for-loop*: \n", - "`- global_namespace = {'a_name':object1, ...}`\n", - "\n", - "*during the for-loop*: \n", - "`- global_namespace = {'a_name':object1, ...}` \n", - "`- for-loop_namespace = {'a':object201, ...}`\n", - "\n", - "*after the for-loop*: \n", - "`- global_namespace = {'a_name':object1, ...}`\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**However, this does not apply if we defined the `for-loop` variable in the global namespace before!**" + "**This also applies if we explicitely defined the `for-loop` variable in the global namespace before!** In this case it will rebind the existing variable:" ] }, { @@ -1021,13 +1002,13 @@ ] } ], - "prompt_number": 7 + "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In **Python 3.4**, we can use closures to prevent the for-loop variable to cut into the global namespace. Here is an example (exectuted in Python 3.4):" + "However, in **Python 3.x**, we can use closures to prevent the for-loop variable to cut into the global namespace. Here is an example (exectuted in Python 3.4):" ] }, { @@ -1056,12 +1037,20 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Why did I mention \"Python 3.4\"? Well, as it happens, the same code executed in Python 2.x would print:\n", + "Why did I mention \"Python 3.x\"? Well, as it happens, the same code executed in Python 2.x would print:\n", "\n", "
\n",
       "print(4, '-> i in global')\n",
       "
"
      ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
     }
    ],
    "metadata": {}

From 3e6588120f40ec7f2bd8e7b45124a72b0d35d352 Mon Sep 17 00:00:00 2001
From: Sebastian Raschka 
Date: Tue, 29 Apr 2014 21:38:56 -0400
Subject: [PATCH 14/26]  fixed for-loop example

---
 tutorials/scope_resolution_legb_rule.ipynb | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb
index 2ee602a..32f9626 100644
--- a/tutorials/scope_resolution_legb_rule.ipynb
+++ b/tutorials/scope_resolution_legb_rule.ipynb
@@ -593,7 +593,8 @@
      "cell_type": "markdown",
      "metadata": {},
      "source": [
-      "Similar to the concept of the `global` keyword, which we have seen in the section above, we can use the keyword `nonlocal` inside the inner function to explicitely access a variable from the outer (enclosed) scope in order to modify its value:"
+      "Similar to the concept of the `global` keyword, which we have seen in the section above, we can use the keyword `nonlocal` inside the inner function to explicitely access a variable from the outer (enclosed) scope in order to modify its value.  \n",
+      "Note that the `nonlocal` keyword was added in Python 3.x and is not implemented in Python 2.x (yet)."
      ]
     },
     {
@@ -1045,12 +1046,13 @@
      ]
     },
     {
-     "cell_type": "code",
-     "collapsed": false,
-     "input": [],
-     "language": "python",
+     "cell_type": "markdown",
      "metadata": {},
-     "outputs": []
+     "source": [
+      "This goes back to a change that was made in Python 3.x and is described in [What\u2019s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) as follows:\n",
+      "\n",
+      "\"List comprehensions no longer support the syntactic form `[... for var in item1, item2, ...]`. Use `[... for var in (item1, item2, ...)]` instead. Also note that list comprehensions have different semantics: they are closer to syntactic sugar for a generator expression inside a `list()` constructor, and in particular the loop control variables are no longer leaked into the surrounding scope.\""
+     ]
     }
    ],
    "metadata": {}

From 13046927a3d9d42a225661e1e91e8bbbe7f6c15f Mon Sep 17 00:00:00 2001
From: Sebastian Raschka 
Date: Tue, 29 Apr 2014 21:40:39 -0400
Subject: [PATCH 15/26]  fixed for-loop example

---
 tutorials/scope_resolution_legb_rule.ipynb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb
index 32f9626..4eb32d6 100644
--- a/tutorials/scope_resolution_legb_rule.ipynb
+++ b/tutorials/scope_resolution_legb_rule.ipynb
@@ -65,7 +65,7 @@
       "- [Self-assessment exercise](#assessment)\n",
       "- [Conclusion](#conclusion)  \n",
       "- [Solutions](#solutions)\n",
-      "- [Warning: For-loop variables cutting into the global namespace](#for_loop)"
+      "- [Warning: For-loop variables \"leaking\" into the global namespace](#for_loop)"
      ]
     },
     {
@@ -941,7 +941,7 @@
      "cell_type": "markdown",
      "metadata": {},
      "source": [
-      "## Warning: For-loop variables cutting into the global namespace"
+      "## Warning: For-loop variables \"leaking\" into the global namespace"
      ]
     },
     {

From bea168e07bae1b13692e9be2b84ad800cb7c9e8f Mon Sep 17 00:00:00 2001
From: Sebastian Raschka 
Date: Tue, 29 Apr 2014 21:43:29 -0400
Subject: [PATCH 16/26]  fixed for-loop example

---
 tutorials/scope_resolution_legb_rule.ipynb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb
index 4eb32d6..57d4490 100644
--- a/tutorials/scope_resolution_legb_rule.ipynb
+++ b/tutorials/scope_resolution_legb_rule.ipynb
@@ -503,8 +503,8 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "print(global()) # prints global namespace\n",
-      "print(local()) # prints local namespace"
+      "print(globals()) # prints global namespace\n",
+      "print(locals()) # prints local namespace"
      ],
      "language": "python",
      "metadata": {},

From dd25efd41f33986e92180e7982e1502ad183f744 Mon Sep 17 00:00:00 2001
From: Sebastian Raschka 
Date: Tue, 29 Apr 2014 21:55:50 -0400
Subject: [PATCH 17/26]  fixed for-loop example

---
 tutorials/scope_resolution_legb_rule.ipynb | 63 ++++++++++++++--------
 1 file changed, 42 insertions(+), 21 deletions(-)

diff --git a/tutorials/scope_resolution_legb_rule.ipynb b/tutorials/scope_resolution_legb_rule.ipynb
index 57d4490..1ad6b74 100644
--- a/tutorials/scope_resolution_legb_rule.ipynb
+++ b/tutorials/scope_resolution_legb_rule.ipynb
@@ -176,7 +176,7 @@
        ]
       }
      ],
-     "prompt_number": 4
+     "prompt_number": 1
     },
     {
      "cell_type": "markdown",
@@ -200,6 +200,47 @@
       "So, how does Python now which namespace it has to search if we want to print the value of the variable `i`? This is where Python's LEGB-rule comes into play, which we will discuss in the next section."
      ]
     },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "### Tip:\n",
+      "If we want to print out the dictionary mapping of the global and local variables, we can use the\n",
+      "the functions `global()` and `local()"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "#print(globals()) # prints global namespace\n",
+      "#print(locals()) # prints local namespace\n",
+      "\n",
+      "glob = 1\n",
+      "\n",
+      "def foo():\n",
+      "    loc = 5\n",
+      "    print('loc in foo():', 'loc' in locals())\n",
+      "\n",
+      "foo()\n",
+      "print('loc in global:', 'loc' in globals())    \n",
+      "print('glob in global:', 'foo' in globals())"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": [
+      {
+       "output_type": "stream",
+       "stream": "stdout",
+       "text": [
+        "loc in foo(): True\n",
+        "loc in global: False\n",
+        "glob in global: True\n"
+       ]
+      }
+     ],
+     "prompt_number": 11
+    },
     {
      "cell_type": "markdown",
      "metadata": {},
@@ -490,26 +531,6 @@
       "
" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Tip:\n", - "If we want to print out the dictionary mapping of the global and local variables, we can use the\n", - "the functions `global()` and `local()" - ] - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "print(globals()) # prints global namespace\n", - "print(locals()) # prints local namespace" - ], - "language": "python", - "metadata": {}, - "outputs": [] - }, { "cell_type": "markdown", "metadata": {}, From 11ace287f86789d7fe1a3c6adc338f2eaed76058 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Tue, 29 Apr 2014 22:28:50 -0400 Subject: [PATCH 18/26] new dir for py files --- closures.py => howtos_as_py_files/closures.py | 0 .../cmd_line_args_1_sysarg.py | 0 cpu_time.py => howtos_as_py_files/cpu_time.py | 0 .../date_time.py | 0 .../diff_files.py | 0 .../doctest_example.py | 0 .../file_browsing.py | 0 .../get_filename.py | 0 .../get_minmax_indeces.py | 0 .../normalize_data.py | 0 .../numpy_matrix.py | 0 howtos_as_py_files/os_shutil_fileops.py | 22 +++++++++++++++++++ .../pickle_module.py | 0 .../pil_image_processing.py | 0 .../python2_vs_3_version_info.py | 0 .../read_file.py | 0 .../reg_expr_1_basics.py | 0 .../reg_expr_2_operators.py | 0 .../timeit_test.py | 0 .../zen_of_python.py | 0 20 files changed, 22 insertions(+) rename closures.py => howtos_as_py_files/closures.py (100%) rename cmd_line_args_1_sysarg.py => howtos_as_py_files/cmd_line_args_1_sysarg.py (100%) rename cpu_time.py => howtos_as_py_files/cpu_time.py (100%) rename date_time.py => howtos_as_py_files/date_time.py (100%) rename diff_files.py => howtos_as_py_files/diff_files.py (100%) rename doctest_example.py => howtos_as_py_files/doctest_example.py (100%) rename file_browsing.py => howtos_as_py_files/file_browsing.py (100%) rename get_filename.py => howtos_as_py_files/get_filename.py (100%) rename get_minmax_indeces.py => howtos_as_py_files/get_minmax_indeces.py (100%) rename normalize_data.py => howtos_as_py_files/normalize_data.py (100%) rename numpy_matrix.py => howtos_as_py_files/numpy_matrix.py (100%) create mode 100644 howtos_as_py_files/os_shutil_fileops.py rename pickle_module.py => howtos_as_py_files/pickle_module.py (100%) rename pil_image_processing.py => howtos_as_py_files/pil_image_processing.py (100%) rename python2_vs_3_version_info.py => howtos_as_py_files/python2_vs_3_version_info.py (100%) rename read_file.py => howtos_as_py_files/read_file.py (100%) rename reg_expr_1_basics.py => howtos_as_py_files/reg_expr_1_basics.py (100%) rename reg_expr_2_operators.py => howtos_as_py_files/reg_expr_2_operators.py (100%) rename timeit_test.py => howtos_as_py_files/timeit_test.py (100%) rename zen_of_python.py => howtos_as_py_files/zen_of_python.py (100%) diff --git a/closures.py b/howtos_as_py_files/closures.py similarity index 100% rename from closures.py rename to howtos_as_py_files/closures.py diff --git a/cmd_line_args_1_sysarg.py b/howtos_as_py_files/cmd_line_args_1_sysarg.py similarity index 100% rename from cmd_line_args_1_sysarg.py rename to howtos_as_py_files/cmd_line_args_1_sysarg.py diff --git a/cpu_time.py b/howtos_as_py_files/cpu_time.py similarity index 100% rename from cpu_time.py rename to howtos_as_py_files/cpu_time.py diff --git a/date_time.py b/howtos_as_py_files/date_time.py similarity index 100% rename from date_time.py rename to howtos_as_py_files/date_time.py diff --git a/diff_files.py b/howtos_as_py_files/diff_files.py similarity index 100% rename from diff_files.py rename to howtos_as_py_files/diff_files.py diff --git a/doctest_example.py b/howtos_as_py_files/doctest_example.py similarity index 100% rename from doctest_example.py rename to howtos_as_py_files/doctest_example.py diff --git a/file_browsing.py b/howtos_as_py_files/file_browsing.py similarity index 100% rename from file_browsing.py rename to howtos_as_py_files/file_browsing.py diff --git a/get_filename.py b/howtos_as_py_files/get_filename.py similarity index 100% rename from get_filename.py rename to howtos_as_py_files/get_filename.py diff --git a/get_minmax_indeces.py b/howtos_as_py_files/get_minmax_indeces.py similarity index 100% rename from get_minmax_indeces.py rename to howtos_as_py_files/get_minmax_indeces.py diff --git a/normalize_data.py b/howtos_as_py_files/normalize_data.py similarity index 100% rename from normalize_data.py rename to howtos_as_py_files/normalize_data.py diff --git a/numpy_matrix.py b/howtos_as_py_files/numpy_matrix.py similarity index 100% rename from numpy_matrix.py rename to howtos_as_py_files/numpy_matrix.py diff --git a/howtos_as_py_files/os_shutil_fileops.py b/howtos_as_py_files/os_shutil_fileops.py new file mode 100644 index 0000000..d517f22 --- /dev/null +++ b/howtos_as_py_files/os_shutil_fileops.py @@ -0,0 +1,22 @@ +# sr 11/19/2013 +# common file operations in os and shutil modules + +import shutil +import os + +# Getting files of particular type from directory +files = [f for f in os.listdir(s_pdb_dir) if f.endswith(".txt")] + +# Copy and move +shutil.copyfile("/path/to/file", "/path/to/new/file") +shutil.copy("/path/to/file", "/path/to/directory") +shutil.move("/path/to/file","/path/to/directory") + +# Check if file or directory exists +os.path.exists("file or directory") +os.path.isfile("file") +os.path.isdir("directory") + +# Working directory and absolute path to files +os.getcwd() +os.path.abspath("file") diff --git a/pickle_module.py b/howtos_as_py_files/pickle_module.py similarity index 100% rename from pickle_module.py rename to howtos_as_py_files/pickle_module.py diff --git a/pil_image_processing.py b/howtos_as_py_files/pil_image_processing.py similarity index 100% rename from pil_image_processing.py rename to howtos_as_py_files/pil_image_processing.py diff --git a/python2_vs_3_version_info.py b/howtos_as_py_files/python2_vs_3_version_info.py similarity index 100% rename from python2_vs_3_version_info.py rename to howtos_as_py_files/python2_vs_3_version_info.py diff --git a/read_file.py b/howtos_as_py_files/read_file.py similarity index 100% rename from read_file.py rename to howtos_as_py_files/read_file.py diff --git a/reg_expr_1_basics.py b/howtos_as_py_files/reg_expr_1_basics.py similarity index 100% rename from reg_expr_1_basics.py rename to howtos_as_py_files/reg_expr_1_basics.py diff --git a/reg_expr_2_operators.py b/howtos_as_py_files/reg_expr_2_operators.py similarity index 100% rename from reg_expr_2_operators.py rename to howtos_as_py_files/reg_expr_2_operators.py diff --git a/timeit_test.py b/howtos_as_py_files/timeit_test.py similarity index 100% rename from timeit_test.py rename to howtos_as_py_files/timeit_test.py diff --git a/zen_of_python.py b/howtos_as_py_files/zen_of_python.py similarity index 100% rename from zen_of_python.py rename to howtos_as_py_files/zen_of_python.py From d1f0f9b4add683b4df4e944e2bcc6f8a60833757 Mon Sep 17 00:00:00 2001 From: Sebastian Raschka Date: Tue, 29 Apr 2014 22:49:59 -0400 Subject: [PATCH 19/26] sqlite tutorial --- .DS_Store | Bin 12292 -> 0 bytes sqlite3/README.md | 4 - sqlite3/create_db.py | 30 - sqlite3/query_db.py | 28 - sqlite3/update_db.py | 46 - sqlite3_howto/Images/1_sqlite3_init_db.png | Bin 0 -> 58744 bytes sqlite3_howto/Images/2_sqlite3_add_col.png | Bin 0 -> 22346 bytes .../Images/3_sqlite3_insert_update.png | Bin 0 -> 27977 bytes .../Images/4_sqlite3_unique_index.png | Bin 0 -> 31320 bytes sqlite3_howto/Images/5_sqlite3_date_time.png | Bin 0 -> 26319 bytes .../Images/5_sqlite3_date_time_2.png | Bin 0 -> 3035 bytes .../Images/6_sqlite3_print_selecting_rows.png | Bin 0 -> 5936 bytes .../Images/7_sqlite3_get_colnames_1.png | Bin 0 -> 29155 bytes .../Images/7_sqlite3_get_colnames_2.png | Bin 0 -> 4708 bytes .../Images/8_sqlite3_print_db_info_1.png | Bin 0 -> 29155 bytes .../Images/8_sqlite3_print_db_info_2.png | Bin 0 -> 16363 bytes sqlite3_howto/Images/sqlite_python_logo.png | Bin 0 -> 158743 bytes sqlite3_howto/LICENSE | 674 +++++++++++++++ sqlite3_howto/README.md | 784 ++++++++++++++++++ sqlite3_howto/code/add_new_column.py | 28 + sqlite3_howto/code/create_new_db.py | 27 + sqlite3_howto/code/create_unique_index.py | 34 + sqlite3_howto/code/date_time_ops.py | 69 ++ sqlite3_howto/code/get_columnnames.py | 24 + sqlite3_howto/code/print_db_info.py | 91 ++ sqlite3_howto/code/selecting_entries.py | 51 ++ .../code/update_or_insert_records.py | 35 + sqlite3_howto/code/updating_rows.py | 50 ++ sqlite3_howto/code/write_from_sqlite.py | 102 +++ 29 files changed, 1969 insertions(+), 108 deletions(-) delete mode 100644 .DS_Store delete mode 100644 sqlite3/README.md delete mode 100644 sqlite3/create_db.py delete mode 100644 sqlite3/query_db.py delete mode 100644 sqlite3/update_db.py create mode 100644 sqlite3_howto/Images/1_sqlite3_init_db.png create mode 100644 sqlite3_howto/Images/2_sqlite3_add_col.png create mode 100644 sqlite3_howto/Images/3_sqlite3_insert_update.png create mode 100644 sqlite3_howto/Images/4_sqlite3_unique_index.png create mode 100644 sqlite3_howto/Images/5_sqlite3_date_time.png create mode 100644 sqlite3_howto/Images/5_sqlite3_date_time_2.png create mode 100644 sqlite3_howto/Images/6_sqlite3_print_selecting_rows.png create mode 100644 sqlite3_howto/Images/7_sqlite3_get_colnames_1.png create mode 100644 sqlite3_howto/Images/7_sqlite3_get_colnames_2.png create mode 100644 sqlite3_howto/Images/8_sqlite3_print_db_info_1.png create mode 100644 sqlite3_howto/Images/8_sqlite3_print_db_info_2.png create mode 100644 sqlite3_howto/Images/sqlite_python_logo.png create mode 100644 sqlite3_howto/LICENSE create mode 100644 sqlite3_howto/README.md create mode 100644 sqlite3_howto/code/add_new_column.py create mode 100644 sqlite3_howto/code/create_new_db.py create mode 100644 sqlite3_howto/code/create_unique_index.py create mode 100644 sqlite3_howto/code/date_time_ops.py create mode 100644 sqlite3_howto/code/get_columnnames.py create mode 100644 sqlite3_howto/code/print_db_info.py create mode 100644 sqlite3_howto/code/selecting_entries.py create mode 100644 sqlite3_howto/code/update_or_insert_records.py create mode 100644 sqlite3_howto/code/updating_rows.py create mode 100644 sqlite3_howto/code/write_from_sqlite.py diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 4732423c71b8ccc2afb4018e2a292d0242b9e28c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12292 zcmeI1Uu+ab9LImZYoR-|lxZpSI0P@$S|o?|_}4ZlT-)Q17DMB;y;9I~?{=XZw!8Iq z?~Yg-YoZYqh#EBU#RxB&s);X}=!@||qrB(?CJ^z(H=j(@2Os^-&Xz#igT#=~$V{^H zoB7TBc4xo)nVp+G0KmSIkpzeWfJTR~yq>Z}l4uvlf)oiob!3s^0mfkhbST0}@D}t| z4yAxnKq;UUPzopomVyGbW{ad%S@&hD%9R32fqPN`@qUQYA#5tNGtvgH4$6Wp0NGk{ z2Z_qG4+vu7p-qK$M%o~h&M9{f7=~iF#XuQO?QzkaY$~)f(#mi^84eg;8N(e423M!J zc+ed%C9TSp0!o2}3W&Y?3dn;A4is+OzvnC7WZri3)P5~LXIo{ImI=*f>W-$o143oMX z%UX`%R{GqMV|d3h(wVgke>^y8=+HE#u^f+1O(m1t6Y=EsUDJv9R9E+oM7*n~XL_2S zW7@io?Ry9E?hB`1d;N_wXFr;iw~XOy1DfVZ@Nu>KFK3F5?K&r@UBos*iN0x=aGb0S zIVuE-w;j~IKr;5vgvvrIf?3$9(7aHyrJpxcEKbvAo# zJ7Ya>dZWI1$`_?E&n^1>LB~;xVudfqn??NLN#AlEZ^SHmWEq=nSQFdWwt4Heu17Dg zY+S`zGi%9~Ezio^=5R#-c|`XLrej#ni7~>|@vY;QS!7L-HEhVyCrlaD8ePZu=h`uY zhV!Irh(1Qp5^arc(6pn%-(NH-mu?o1Zem>5hCCXYJViU}VBBLvCuwHL&@C*Xaf1!p zdfv39>k*dJ_yEh6<@lv@2iv7JVS6Q!= zn&Epdl3fhV*#6ZA(su>Ts|^CkrsmZxYeGVMuRq~=5A{aA0;D7}0ZVhN1hn1^=vu-y zww`UMhQctRXr2n#;&qpU-tpKb0TtI|wLR9M5%)Y2RN0nTLQu_XWNSdH!T2)SN}LM9 zd97^iVZ`SEwkENN$aS;To0(gP&`;y?h1V6#g@GJZVf51P4+;Zf& z7F#h!$Zfy}u>&8%EttTaxC^_n2X_;2`|toB#3wL=Lj+!y(908gCLYIed=87~V+kub zgD>IB_zJ#CAijlf<9U1s-=Bxz!8!P(#Sd?X;Jl^h=I}dMtC8o5iv9n->fitG;1$)W zlmbeDrKSMZrZee28r9sQIe&m+uN|l3Svo`#{br;MLMRKi<79*FIN9re7*aV-T}4bP zv@_C@htgg65TMq7@mp7||M&X(AIv|MDFu`QN&%&SQa~x76i^B%1(X6x0i}RaKq>J5 GRp4Lt_NgHN diff --git a/sqlite3/README.md b/sqlite3/README.md deleted file mode 100644 index 7fc1e51..0000000 --- a/sqlite3/README.md +++ /dev/null @@ -1,4 +0,0 @@ -sqlite3_examples -================ - -Syntax examples for working with SQLite databases via the sqlite3 module in Python diff --git a/sqlite3/create_db.py b/sqlite3/create_db.py deleted file mode 100644 index 7099675..0000000 --- a/sqlite3/create_db.py +++ /dev/null @@ -1,30 +0,0 @@ -# 10/28/2013 Sebastian Raschka -# Syntax basics for creating sqlite3 data bases - -import sqlite3 - -# create new db and make connection -conn = sqlite3.connect('zinc_db1.db') -c = conn.cursor() - -# create table -c.execute('''CREATE TABLE zinc_db1 - (zinc_id PRIMARY KEY, purchasable TEXT, non_rot_bonds INT)''') - -# Insert one row of data -c.execute("INSERT INTO zinc_db1 VALUES ('ZINC00895032','YES', 4)") - -# Insert multiple lines of data -multi_lines =[ ('ZINC00895033','YES', 1), - ('ZINC00895034','NO', 0), - ('ZINC00895035','YES', 3), - ('ZINC00895036','YES', 9), - ('ZINC00895037','YES', 10) - ] -c.executemany('INSERT INTO zinc_db1 VALUES (?,?,?)', multi_lines) - -# Save (commit) the changes -conn.commit() - -# close connection -conn.close() diff --git a/sqlite3/query_db.py b/sqlite3/query_db.py deleted file mode 100644 index 40bd2d7..0000000 --- a/sqlite3/query_db.py +++ /dev/null @@ -1,28 +0,0 @@ -# 10/28/2013 Sebastian Raschka -# Syntax basics for querying sqlite3 data bases - -import sqlite3 - -# open existing database -conn = sqlite3.connect('zinc_db1.db') -c = conn.cursor() - -# print all lines ordered by number of non_rot_bonds -for row in c.execute('SELECT * FROM zinc_db1 ORDER BY non_rot_bonds'): - print row - -# print all lines that are purchasable and have <= 7 rotatable bonds -t = ('YES',7,) -for row in c.execute('SELECT * FROM zinc_db1 WHERE purchasable=? AND non_rot_bonds <= ?', t): - print row - -# print all lines that are purchasable and have <= 7 rotatable bonds -t = ('YES',7,) -c.execute('SELECT * FROM zinc_db1 WHERE purchasable=? AND non_rot_bonds <= ?', t) -rows = c.fetchall() -for r in rows: - print r - -# close connection -conn.close() - diff --git a/sqlite3/update_db.py b/sqlite3/update_db.py deleted file mode 100644 index 50c4a63..0000000 --- a/sqlite3/update_db.py +++ /dev/null @@ -1,46 +0,0 @@ -# 10/28/2013 Sebastian Raschka -# Syntax basics for updating sqlite3 data bases - -import sqlite3 - -# make connection to existing db -conn = sqlite3.connect('zinc_db1.db') -c = conn.cursor() - -# update field (no insert if id doesn't exist) -t = ('NO', 'ZINC00895033', ) -c.execute("UPDATE zinc_db1 SET purchasable=? WHERE zinc_id=?", t) -print "Total number of rows changed:", conn.total_changes - - -# update, or insert when id does not exist -# here: updates rotatable bonds if record with primary key zinc_id exists,
-# else inserts new record an sets purchasable to 0 -c.execute("""INSERT OR REPLACE INTO zinc_db1 (zinc_id, rotatable_bonds, purchasable) - VALUES ( 'ZINC123456798', - 3, - COALESCE((SELECT purchasable from zinc_db1 WHERE zinc_id = 'ZINC123456798'), 0) - )""") - - - -# delete rows -t = ('NO', ) -c.execute("DELETE FROM zinc_db1 WHERE purchasable=?", t) -print "Total number of rows deleted: ", conn.total_changes - -# add column -c.execute("ALTER TABLE zinc_db1 ADD COLUMN 'keto_oxy' TEXT") - -# save changes -conn.commit() - -# print column names -c.execute("SELECT * FROM zinc_db1") -col_name_list = [tup[0] for tup in c.description] -print col_name_list - - - -# close connection -conn.close() diff --git a/sqlite3_howto/Images/1_sqlite3_init_db.png b/sqlite3_howto/Images/1_sqlite3_init_db.png new file mode 100644 index 0000000000000000000000000000000000000000..c85f420a166a8677ce272a68211d1e5483a4f1f2 GIT binary patch literal 58744 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