From b065840e595212ca82cbbfdfcf00e53359711a3d Mon Sep 17 00:00:00 2001 From: rasbt Date: Thu, 17 Apr 2014 15:39:55 -0400 Subject: [PATCH] looping pitfall --- not_so_obvious_python_stuff.ipynb | 85 ++++++++++++++++--------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/not_so_obvious_python_stuff.ipynb b/not_so_obvious_python_stuff.ipynb index 14fb7c5..03255fd 100644 --- a/not_so_obvious_python_stuff.ipynb +++ b/not_so_obvious_python_stuff.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:be423e458dd8b1ac6a36f49330311cc1a1741127c5610a636969efddf6d91597" + "signature": "sha256:02c6c63beb1de9373d69615a4ba37640a7b01c8f2d088dbfaa84bdaf3452f1c5" }, "nbformat": 3, "nbformat_minor": 0, @@ -63,7 +63,8 @@ "- [Python's LEGB scope resolution and the keywords `global` and `nonlocal`](#python_legb)\n", "- [When mutable contents of immutable tuples aren't so mutable](#immutable_tuple)\n", "- [List comprehensions are fast, but generators are faster!?](#list_generator)\n", - "- [Public vs. private class methods and name mangling](#private_class)" + "- [Public vs. private class methods and name mangling](#private_class)\n", + "- [The consequences of modifying a list when looping through it](#looping_pitfall)" ] }, { @@ -1299,14 +1300,31 @@ ], "prompt_number": 28 }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "\n", + "## The consequences of modifying a list when looping through it" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It can be really dangerous to modify a list when iterating through - it is a very common pitfall that can cause unintended behavour!" + ] + }, { "cell_type": "code", "collapsed": false, "input": [ "a = [1, 2, 3, 4, 5]\n", "for i in a:\n", - " if not i % 2:\n", - " a.remove(i)\n", + " if not i % 2:\n", + " a.remove(i)\n", "print(a)" ], "language": "python", @@ -1320,7 +1338,7 @@ ] } ], - "prompt_number": 1 + "prompt_number": 3 }, { "cell_type": "code", @@ -1343,17 +1361,27 @@ ] } ], - "prompt_number": 7 + "prompt_number": 4 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + "
\n", + "**The solution** is that we are iterating through the list index by index, and if we remove one of the items in-between, we inevitably mess around with the indexing, look at the following example, and it will become clear:" + ] }, { "cell_type": "code", "collapsed": false, "input": [ - "c = [2, 4, 5, 6]\n", - "for i in c:\n", - " if i % 2 != 0:\n", - " c.remove(i)\n", - "print(c)" + "b = [2, 4, 5, 6]\n", + "for index, item in enumerate(b):\n", + " print(index, item)\n", + " if not item % 2:\n", + " b.remove(item)\n", + "print(b)" ], "language": "python", "metadata": {}, @@ -1362,39 +1390,14 @@ "output_type": "stream", "stream": "stdout", "text": [ - "[2, 4, 6]\n" + "0 2\n", + "1 5\n", + "2 6\n", + "[4, 5]\n" ] } ], - "prompt_number": 6 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [ - "not 4 % 2" - ], - "language": "python", - "metadata": {}, - "outputs": [ - { - "metadata": {}, - "output_type": "pyout", - "prompt_number": 9, - "text": [ - "True" - ] - } - ], - "prompt_number": 9 - }, - { - "cell_type": "code", - "collapsed": false, - "input": [], - "language": "python", - "metadata": {}, - "outputs": [] + "prompt_number": 7 } ], "metadata": {}