diff --git a/.ipynb_checkpoints/not_so_obvious_python_stuff-checkpoint.ipynb b/.ipynb_checkpoints/not_so_obvious_python_stuff-checkpoint.ipynb index 171353f..85df945 100644 --- a/.ipynb_checkpoints/not_so_obvious_python_stuff-checkpoint.ipynb +++ b/.ipynb_checkpoints/not_so_obvious_python_stuff-checkpoint.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:faa74a34746bf250ef2d72e308074083ee5e60789203d70f630f8c67a709e6fe" + "signature": "sha256:06e485535e22c756262f09d4477108b57d0fa1029f9831ee77a177267f5afc7f" }, "nbformat": 3, "nbformat_minor": 0, @@ -46,7 +46,8 @@ "- [Don't use mutable objects as default arguments for functions!](#def_mutable_func)\n", "- [Be aware of the consuming generator](#consuming_generator)\n", "- [`bool` is a subclass of `int`](#bool_int)\n", - "- [About lambda and closures-in-a-loop pitfall](#lambda_closure)" + "- [About lambda and closures-in-a-loop pitfall](#lambda_closure)\n", + "- [Python's LEGB scope resolution and the keywords `global` and `nonlocal`](#python_legb)" ] }, { @@ -594,7 +595,9 @@ "\n", "## About lambda and closures-in-a-loop pitfall\n", "\n", - "The following example illustrates how the (last) `lambda` is being reused:" + "The following example illustrates how the (last) `lambda` is being reused:\n", + "\n", + "(Original source: [http://openhome.cc/eGossip/Blog/UnderstandingLambdaClosure3.html](http://openhome.cc/eGossip/Blog/UnderstandingLambdaClosure3.html))" ] }, { @@ -654,13 +657,167 @@ ], "prompt_number": 25 }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "\n", + "\n", + "## Python's LEGB scope resolution and the keywords `global` and `nonlocal`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There is nothing particularly surprising about Python's LEGB scope resolution (Local -> Enclosed -> Global -> Built-in), but it is still useful to take a look at some examples!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `global` vs. `local`\n", + "\n", + "According to the LEGB rule, Python will first look for a variable in the local scope. So if we set the variable `x = 1` in the `local`ly in the function's scope, it won't have an effect on the `global` `x`." + ] + }, { "cell_type": "code", "collapsed": false, - "input": [], + "input": [ + "x = 0\n", + "def in_func():\n", + " x = 1\n", + " print('in_func:', x)\n", + " \n", + "in_func()\n", + "print('global:', x)" + ], "language": "python", "metadata": {}, - "outputs": [] + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "in_func: 1\n", + "global: 0\n" + ] + } + ], + "prompt_number": 33 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we want to modify the `global` x via a function, we can simply use the `global` keyword to import the variable into the function's scope:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = 0\n", + "def in_func():\n", + " global x\n", + " x = 1\n", + " print('in_func:', x)\n", + " \n", + "in_func()\n", + "print('global:', x)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "in_func: 1\n", + "global: 1\n" + ] + } + ], + "prompt_number": 34 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `local` vs. `enclosed`\n", + "\n", + "Now, let us take a look at `local` vs. `enclosed`. Here, we set the variable `x = 1` in the `outer` function and set `x = 1` in the enclosed function `inner`. Since `inner` looks in the local scope first, it won't modify `outer`'s `x`." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "def outer():\n", + " x = 1\n", + " print('outer before:', x)\n", + " def inner():\n", + " x = 2\n", + " print(\"inner:\", x)\n", + " inner()\n", + " print(\"outer after:\", x)\n", + "outer()" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "outer before: 1\n", + "inner: 2\n", + "outer after: 1\n" + ] + } + ], + "prompt_number": 36 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is where the `nonlocal` keyword comes in handy - it allows us to modify the `x` variable in the `enclosed` scope:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "def outer():\n", + " x = 1\n", + " print('outer before:', x)\n", + " def inner():\n", + " nonlocal x\n", + " x = 2\n", + " print(\"inner:\", x)\n", + " inner()\n", + " print(\"outer after:\", x)\n", + "outer()" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "outer before: 1\n", + "inner: 2\n", + "outer after: 2\n" + ] + } + ], + "prompt_number": 35 } ], "metadata": {} diff --git a/not_so_obvious_python_stuff.ipynb b/not_so_obvious_python_stuff.ipynb index 171353f..85df945 100644 --- a/not_so_obvious_python_stuff.ipynb +++ b/not_so_obvious_python_stuff.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:faa74a34746bf250ef2d72e308074083ee5e60789203d70f630f8c67a709e6fe" + "signature": "sha256:06e485535e22c756262f09d4477108b57d0fa1029f9831ee77a177267f5afc7f" }, "nbformat": 3, "nbformat_minor": 0, @@ -46,7 +46,8 @@ "- [Don't use mutable objects as default arguments for functions!](#def_mutable_func)\n", "- [Be aware of the consuming generator](#consuming_generator)\n", "- [`bool` is a subclass of `int`](#bool_int)\n", - "- [About lambda and closures-in-a-loop pitfall](#lambda_closure)" + "- [About lambda and closures-in-a-loop pitfall](#lambda_closure)\n", + "- [Python's LEGB scope resolution and the keywords `global` and `nonlocal`](#python_legb)" ] }, { @@ -594,7 +595,9 @@ "\n", "## About lambda and closures-in-a-loop pitfall\n", "\n", - "The following example illustrates how the (last) `lambda` is being reused:" + "The following example illustrates how the (last) `lambda` is being reused:\n", + "\n", + "(Original source: [http://openhome.cc/eGossip/Blog/UnderstandingLambdaClosure3.html](http://openhome.cc/eGossip/Blog/UnderstandingLambdaClosure3.html))" ] }, { @@ -654,13 +657,167 @@ ], "prompt_number": 25 }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "\n", + "\n", + "## Python's LEGB scope resolution and the keywords `global` and `nonlocal`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There is nothing particularly surprising about Python's LEGB scope resolution (Local -> Enclosed -> Global -> Built-in), but it is still useful to take a look at some examples!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `global` vs. `local`\n", + "\n", + "According to the LEGB rule, Python will first look for a variable in the local scope. So if we set the variable `x = 1` in the `local`ly in the function's scope, it won't have an effect on the `global` `x`." + ] + }, { "cell_type": "code", "collapsed": false, - "input": [], + "input": [ + "x = 0\n", + "def in_func():\n", + " x = 1\n", + " print('in_func:', x)\n", + " \n", + "in_func()\n", + "print('global:', x)" + ], "language": "python", "metadata": {}, - "outputs": [] + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "in_func: 1\n", + "global: 0\n" + ] + } + ], + "prompt_number": 33 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we want to modify the `global` x via a function, we can simply use the `global` keyword to import the variable into the function's scope:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "x = 0\n", + "def in_func():\n", + " global x\n", + " x = 1\n", + " print('in_func:', x)\n", + " \n", + "in_func()\n", + "print('global:', x)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "in_func: 1\n", + "global: 1\n" + ] + } + ], + "prompt_number": 34 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `local` vs. `enclosed`\n", + "\n", + "Now, let us take a look at `local` vs. `enclosed`. Here, we set the variable `x = 1` in the `outer` function and set `x = 1` in the enclosed function `inner`. Since `inner` looks in the local scope first, it won't modify `outer`'s `x`." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "def outer():\n", + " x = 1\n", + " print('outer before:', x)\n", + " def inner():\n", + " x = 2\n", + " print(\"inner:\", x)\n", + " inner()\n", + " print(\"outer after:\", x)\n", + "outer()" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "outer before: 1\n", + "inner: 2\n", + "outer after: 1\n" + ] + } + ], + "prompt_number": 36 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here is where the `nonlocal` keyword comes in handy - it allows us to modify the `x` variable in the `enclosed` scope:" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "def outer():\n", + " x = 1\n", + " print('outer before:', x)\n", + " def inner():\n", + " nonlocal x\n", + " x = 2\n", + " print(\"inner:\", x)\n", + " inner()\n", + " print(\"outer after:\", x)\n", + "outer()" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "outer before: 1\n", + "inner: 2\n", + "outer after: 2\n" + ] + } + ], + "prompt_number": 35 } ], "metadata": {}