From 73979bb5e59e8f95b1533c95fb808b0854ca0e36 Mon Sep 17 00:00:00 2001 From: rasbt Date: Sat, 24 May 2014 12:02:03 -0400 Subject: [PATCH] unorderable types update and separate python 2.x vs. 3.x section --- README.md | 2 + not_so_obvious_python_stuff.ipynb | 379 +++++++++++++++- .../key_differences_between_python_2_and_3.md | 411 ++++++++++++++++++ 3 files changed, 777 insertions(+), 15 deletions(-) create mode 100644 tutorials/key_differences_between_python_2_and_3.md diff --git a/README.md b/README.md index 710e62b..db00ca9 100755 --- a/README.md +++ b/README.md @@ -18,8 +18,10 @@ A collection of useful scripts, tutorials, and other Python-related things - A collection of not so obvious Python stuff you should know! [[IPython nb](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 [[IPython nb](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/tutorials/scope_resolution_legb_rule.ipynb?create=1)] +- Key differences between Python 2.x and Python 3.x [[Markdown](./tutorials/key_differences_python2_python3.md)] - A thorough guide to SQLite database operations in Python [[Markdown](./sqlite3_howto/README.md)] diff --git a/not_so_obvious_python_stuff.ipynb b/not_so_obvious_python_stuff.ipynb index 0a9632c..c36c0dc 100644 --- a/not_so_obvious_python_stuff.ipynb +++ b/not_so_obvious_python_stuff.ipynb @@ -1,7 +1,7 @@ { "metadata": { "name": "", - "signature": "sha256:7a22f6c91e4aab51a325c721dd7674622d1acc5b4a3a038ff512c736d83bbe4a" + "signature": "sha256:b37510e2c48c9811f7baabeff25c48a186e0e5f154b5d341f4eda6701df705e3" }, "nbformat": 3, "nbformat_minor": 0, @@ -13,7 +13,7 @@ "metadata": {}, "source": [ "[Sebastian Raschka](http://sebastianraschka.com) \n", - "last updated: 05/03/2014 ([Changelog](#changelog))\n", + "last updated: 05/24/2014 ([Changelog](#changelog))\n", "\n", "- [Link to this IPython Notebook on GitHub](https://github.com/rasbt/python_reference/blob/master/not_so_obvious_python_stuff.ipynb) \n", "- [Link to the GitHub repository](https://github.com/rasbt/python_reference) \n", @@ -24,7 +24,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### All code was executed in Python 3.4" + "#### All code was executed in Python 3.4 (unless stated otherwise)" ] }, { @@ -59,32 +59,59 @@ "source": [ "# Sections\n", "- [The C3 class resolution algorithm for multiple class inheritance](#c3_class_res)\n", + "\n", "- [Assignment operators and lists - simple-add vs. add-AND operators](#pm_in_lists)\n", + "\n", "- [`True` and `False` in the datetime module](#datetime_module)\n", + "\n", "- [Python reuses objects for small integers - always use \"==\" for equality, \"is\" for identity](#python_small_int)\n", + "\n", "- [Shallow vs. deep copies if list contains other structures and objects](#shallow_vs_deep)\n", + "\n", "- [Picking `True` values from logical `and`s and `or`s](#false_true_expressions)\n", + "\n", "- [Don't use mutable objects as default arguments for functions!](#def_mutable_func)\n", + "\n", "- [Be aware of the consuming generator](#consuming_generator)\n", + "\n", "- [`bool` is a subclass of `int`](#bool_int)\n", + "\n", "- [About lambda-in-closures and-a-loop pitfall](#lambda_closure)\n", + "\n", "- [Python's LEGB scope resolution and the keywords `global` and `nonlocal`](#python_legb)\n", + "\n", "- [When mutable contents of immutable tuples aren't so mutable](#immutable_tuple)\n", + "\n", "- [List comprehensions are fast, but generators are faster!?](#list_generator)\n", + "\n", "- [Public vs. private class methods and name mangling](#private_class)\n", + "\n", "- [The consequences of modifying a list when looping through it](#looping_pitfall)\n", + "\n", "- [Dynamic binding and typos in variable names](#dynamic_binding)\n", + "\n", "- [List slicing using indexes that are \"out of range](#out_of_range_slicing)\n", + "\n", "- [Reusing global variable names and UnboundLocalErrors](#unboundlocalerror)\n", + "\n", "- [Creating copies of mutable objects](#copy_mutable)\n", + "\n", "- [Key differences between Python 2 and 3](#python_differences)\n", + "\n", "- [Function annotations - What are those `->`'s in my Python code?](#function_annotation)\n", + "\n", "- [Abortive statements in `finally` blocks](#finally_blocks)\n", + "\n", "- [Assigning types to variables as values](#variable_types)\n", + "\n", "- [Only the first clause of generators is evaluated immediately](#generator_rhs)\n", + "\n", "- [Keyword argument unpacking syntax - `*args` and `**kwargs`](#splat_op)\n", + "\n", "- [Metaclasses - What creates a new instance of a class?](#new_instance)\n", + "\n", "- [Else-clauses: \"conditional else\" and \"completion else\"](#else_clauses)\n", + "\n", "- [Interning of compile-time constants vs. run-time expressions](#string_interning)" ] }, @@ -2282,12 +2309,69 @@ "(Note: the the code was executed in Python 3.4.0 and Python 2.7.5 and copied from interactive shell sessions.)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Overview - Key differences between Python 2 and 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "- [Unicode](#unicode)\n", + "- [The print statement](#print)\n", + "- [Integer division](#integer_div)\n", + "- [xrange()](#xrange)\n", + "- [Raising exceptions](#raising_exceptions)\n", + "- [Handling exceptions](#handling_exceptions)\n", + "- [next() function and .next() method](#next_next)\n", + "- [Loop variables and leaking into the global scope](#loop_leak)\n", + "- [Comparing unorderable types](#compare_unorder)\n", + "\n", + "
\n", + "
\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Unicode..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[back to Python 2.x vs 3.x overview](#py23_overview)]" + ] + }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", - "### Unicode...\n", "####- Python 2: \n", "We have ASCII `str()` types, separate `unicode()`, but no `byte` type\n", "####- Python 3: \n", @@ -2341,7 +2425,29 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### The print statement\n", + "\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The print statement" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[back to Python 2.x vs 3.x overview](#py23_overview)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "Very trivial, but this change makes sense, Python 3 now only accepts `print`s with proper parentheses - just like the other function calls ..." ] }, @@ -2395,7 +2501,29 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Integer division\n", + "\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Integer division" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[back to Python 2.x vs 3.x overview](#py23_overview)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "This is a pretty dangerous thing if you are porting code, or executing Python 3 code in Python 2 since the change in integer-division behavior can often go unnoticed. \n", "So, I still tend to use a `float(3)/2` or `3/2.0` instead of a `3/2` in my Python 3 scripts to save the Python 2 guys some trouble ... (PS: and vice versa, you can `from __future__ import division` in your Python 2 scripts)." ] @@ -2432,7 +2560,30 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### `xrange()` \n", + "\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "###`xrange()` " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[back to Python 2.x vs 3.x overview](#py23_overview)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \n", "`xrange()` was pretty popular in Python 2.x if you wanted to create an iterable object. The behavior was quite similar to a generator ('lazy evaluation'), but you could iterate over it infinitely. The advantage was that it was generally faster than `range()` (e.g., in a for-loop) - not if you had to iterate over the list multiple times, since the generation happens every time from scratch! \n", "In Python 3, the `range()` was implemented like the `xrange()` function so that a dedicated `xrange()` function does not exist anymore." ] @@ -2470,7 +2621,30 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Raising exceptions\n", + "\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Raising exceptions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[back to Python 2.x vs 3.x overview](#py23_overview)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", "\n", "Where Python 2 accepts both notations, the 'old' and the 'new' way, Python 3 chokes (and raises a `SyntaxError` in turn) if we don't enclose the exception argument in parentheses:" ] @@ -2509,9 +2683,32 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### Handling exceptions\n", + "\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Handling exceptions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[back to Python 2.x vs 3.x overview](#py23_overview)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "\n", - "Also the handling of excecptions has slightly changed in Python 3. Now, we have to use the `as` keyword!" + "\n", + "Also the handling of exceptions has slightly changed in Python 3. Now, we have to use the `as` keyword!" ] }, { @@ -2538,11 +2735,37 @@ "metadata": {}, "outputs": [] }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "\n", + "
\n", + "
" + ], + "language": "python", + "metadata": {}, + "outputs": [] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "#### The `next()` function and `.next()` method\n", + "### The `next()` function and `.next()` method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[back to Python 2.x vs 3.x overview](#py23_overview)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", "\n", "Where you can use both function and method in Python 2.7.5, the `next()` function is all that remain in Python 3!" ] @@ -2575,7 +2798,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### In Python 3.x for-loop variables don't leak into the global namespace anymore" + "\n", + "
\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### In Python 3.x for-loop variables don't leak into the global namespace anymore" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[back to Python 2.x vs 3.x overview](#py23_overview)]" ] }, { @@ -2591,6 +2830,9 @@ "cell_type": "code", "collapsed": false, "input": [ + "from platform import python_version\n", + "print('This code cell was executed in Python', python_version())\n", + "\n", "i = 1\n", "print([i for i in range(5)])\n", "print(i, '-> i in global')" @@ -2602,21 +2844,124 @@ "output_type": "stream", "stream": "stdout", "text": [ + "This code cell was executed in Python 3.3.5\n", "[0, 1, 2, 3, 4]\n", "1 -> i in global\n" ] } ], - "prompt_number": 1 + "prompt_number": 4 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from platform import python_version\n", + "print 'This code cell was executed in Python', python_version()\n", + "\n", + "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": [ + "This code cell was executed in Python 2.7.6\n", + "[0, 1, 2, 3, 4]\n", + "4 -> i in global\n" + ] + } + ], + "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "In Python 2.x this would print \n", - "`4 -> i in global`" + "\n", + "
\n", + "
" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Python 3.x prevents us from comparing unorderable types" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "[[back to Python 2.x vs 3.x overview](#py23_overview)]" + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from platform import python_version\n", + "print 'This code cell was executed in Python', python_version()\n", + "\n", + "print [1, 2] > 'foo'\n", + "print (1, 2) > 'foo'\n", + "print [1, 2] > (1, 2)" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "This code cell was executed in Python 2.7.6\n", + "False\n", + "True\n", + "False\n" + ] + } + ], + "prompt_number": 8 + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "from platform import python_version\n", + "print('This code cell was executed in Python', python_version())\n", + "\n", + "print([1, 2] > 'foo')\n", + "print((1, 2) > 'foo')\n", + "print([1, 2] > (1, 2))" + ], + "language": "python", + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "This code cell was executed in Python 3.3.5\n" + ] + }, + { + "ename": "TypeError", + "evalue": "unorderable types: list() > str()", + "output_type": "pyerr", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'This code cell was executed in Python'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpython_version\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[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;34m'foo'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;34m'foo'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypeError\u001b[0m: unorderable types: list() > str()" + ] + } + ], + "prompt_number": 3 + }, { "cell_type": "markdown", "metadata": {}, @@ -3936,6 +4281,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "#### 05/24/2014\n", + "- new section: unorderable types in Python 2\n", + "- table of contents for the Python 2 vs. Python 3 topic\n", + " \n", "#### 05/03/2014\n", "- new section: else clauses: conditional vs. completion\n", "- new section: Interning of compile-time constants vs. run-time expressions\n", diff --git a/tutorials/key_differences_between_python_2_and_3.md b/tutorials/key_differences_between_python_2_and_3.md new file mode 100644 index 0000000..d7a7d78 --- /dev/null +++ b/tutorials/key_differences_between_python_2_and_3.md @@ -0,0 +1,411 @@ +[Sebastian Raschka](http://sebastianraschka.com) +last updated: 05/24/2014 + +
+ +**This is a subsection of ["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)** + + + +
+ +## Key differences between Python 2 and 3 +
+ +There are some good articles already that are summarizing the differences between Python 2 and 3, e.g., +- [https://wiki.python.org/moin/Python2orPython3](https://wiki.python.org/moin/Python2orPython3) +- [https://docs.python.org/3.0/whatsnew/3.0.html](https://docs.python.org/3.0/whatsnew/3.0.html) +- [http://python3porting.com/differences.html](http://python3porting.com/differences.html) +- [https://docs.python.org/3/howto/pyporting.html](https://docs.python.org/3/howto/pyporting.html) +etc. + +But it might be still worthwhile, especially for Python newcomers, to take a look at some of those! +(Note: the the code was executed in Python 3.4.0 and Python 2.7.5 and copied from interactive shell sessions.) + + + +
+ +### Overview - Key differences between Python 2 and 3 + + + + +- [Unicode](#unicode) +- [The print statement](#print) +- [Integer division](#integer_div) +- [xrange()](#xrange) +- [Raising exceptions](#raising_exceptions) +- [Handling exceptions](#handling_exceptions) +- [next() function and .next() method](#next_next) +- [Loop variables and leaking into the global scope](#loop_leak) +- [Comparing unorderable types](#compare_unorder) + +
+
+ + + +
+
+ +### Unicode... + +[[back to Python 2.x vs 3.x overview](#py23_overview)] + + +####- Python 2: +We have ASCII `str()` types, separate `unicode()`, but no `byte` type +####- Python 3: +Now, we finally have Unicode (utf-8) `str`ings, and 2 byte classes: `byte` and `bytearray`s + +
+ +
#############
+# Python 2
+#############
+
+>>> type(unicode('is like a python3 str()'))
+<type 'unicode'>
+
+>>> type(b'byte type does not exist')
+<type 'str'>
+
+>>> 'they are really' + b' the same'
+'they are really the same'
+
+>>> type(bytearray(b'bytearray oddly does exist though'))
+<type 'bytearray'>
+
+#############
+# Python 3
+#############
+
+>>> print('strings are now utf-8 \u03BCnico\u0394é!')
+strings are now utf-8 μnicoΔé!
+
+
+>>> type(b' and we have byte types for storing data')
+<class 'bytes'>
+
+>>> type(bytearray(b'but also bytearrays for those who prefer them over strings'))
+<class 'bytearray'>
+
+>>> 'string' + b'bytes for data'
+Traceback (most recent call last):s
+  File "<stdin>", line 1, in <module>
+TypeError: Can't convert 'bytes' object to str implicitly
+
+ + + +
+
+ +### The print statement + +[[back to Python 2.x vs 3.x overview](#py23_overview)] + +Very trivial, but this change makes sense, Python 3 now only accepts `print`s with proper parentheses - just like the other function calls ... + +
+
# Python 2
+>>> print 'Hello, World!'
+Hello, World!
+>>> print('Hello, World!')
+Hello, World!
+
+# Python 3
+>>> print('Hello, World!')
+Hello, World!
+>>> print 'Hello, World!'
+  File "<stdin>", line 1
+    print 'Hello, World!'
+                        ^
+SyntaxError: invalid syntax
+
+ +
+ +And if we want to print the output of 2 consecutive print functions on the same line, you would use a comma in Python 2, and a `end=""` in Python 3: + +
+ +
# Python 2
+>>> print "line 1", ; print 'same line'
+line 1 same line
+
+# Python 3
+>>> print("line 1", end="") ; print (" same line")
+line 1 same line
+
+ + + +
+
+ +### Integer division + +[[back to Python 2.x vs 3.x overview](#py23_overview)] + + +This is a pretty dangerous thing if you are porting code, or executing Python 3 code in Python 2 since the change in integer-division behavior can often go unnoticed. +So, I still tend to use a `float(3)/2` or `3/2.0` instead of a `3/2` in my Python 3 scripts to save the Python 2 guys some trouble ... (PS: and vice versa, you can `from __future__ import division` in your Python 2 scripts). + +
+
# Python 2
+>>> 3 / 2
+1
+>>> 3 // 2
+1
+>>> 3 / 2.0
+1.5
+>>> 3 // 2.0
+1.0
+
+# Python 3
+>>> 3 / 2
+1.5
+>>> 3 // 2
+1
+>>> 3 / 2.0
+1.5
+>>> 3 // 2.0
+1.0
+
+ + + +
+
+ +###`xrange()` + +[[back to Python 2.x vs 3.x overview](#py23_overview)] + + +`xrange()` was pretty popular in Python 2.x if you wanted to create an iterable object. The behavior was quite similar to a generator ('lazy evaluation'), but you could iterate over it infinitely. The advantage was that it was generally faster than `range()` (e.g., in a for-loop) - not if you had to iterate over the list multiple times, since the generation happens every time from scratch! +In Python 3, the `range()` was implemented like the `xrange()` function so that a dedicated `xrange()` function does not exist anymore. + + +
# Python 2
+> python -m timeit 'for i in range(1000000):' ' pass'
+10 loops, best of 3: 66 msec per loop
+
+    > python -m timeit 'for i in xrange(1000000):' ' pass'
+10 loops, best of 3: 27.8 msec per loop
+
+# Python 3
+> python3 -m timeit 'for i in range(1000000):' ' pass'
+10 loops, best of 3: 51.1 msec per loop
+
+> python3 -m timeit 'for i in xrange(1000000):' ' pass'
+Traceback (most recent call last):
+  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/timeit.py", line 292, in main
+    x = t.timeit(number)
+  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/timeit.py", line 178, in timeit
+    timing = self.inner(it, self.timer)
+  File "<timeit-src>", line 6, in inner
+    for i in xrange(1000000):
+NameError: name 'xrange' is not defined
+
+ + + +
+
+ +### Raising exceptions + +[[back to Python 2.x vs 3.x overview](#py23_overview)] + + + +Where Python 2 accepts both notations, the 'old' and the 'new' way, Python 3 chokes (and raises a `SyntaxError` in turn) if we don't enclose the exception argument in parentheses: + +
+
# Python 2
+>>> raise IOError, "file error"
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+IOError: file error
+>>> raise IOError("file error")
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+IOError: file error
+
+    
+# Python 3    
+>>> raise IOError, "file error"
+  File "<stdin>", line 1
+    raise IOError, "file error"
+                 ^
+SyntaxError: invalid syntax
+>>> raise IOError("file error")
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+OSError: file error
+
+ + + +
+
+ +### Handling exceptions + +[[back to Python 2.x vs 3.x overview](#py23_overview)] + + + +Also the handling of exceptions has slightly changed in Python 3. Now, we have to use the `as` keyword! + +
# Python 2
+>>> try:
+...     blabla
+... except NameError, err:
+...     print err, '--> our error msg'
+... 
+name 'blabla' is not defined --> our error msg
+
+# Python 3
+>>> try:
+...     blabla
+... except NameError as err:
+...     print(err, '--> our error msg')
+... 
+name 'blabla' is not defined --> our error msg
+
+ + + +
+
+ +### The `next()` function and `.next()` method + +[[back to Python 2.x vs 3.x overview](#py23_overview)] + +Where you can use both function and method in Python 2.7.5, the `next()` function is all that remain in Python 3! + +
# Python 2
+>>> my_generator = (letter for letter in 'abcdefg')
+>>> my_generator.next()
+'a'
+>>> next(my_generator)
+'b'
+
+# Python 3
+>>> my_generator = (letter for letter in 'abcdefg')
+>>> next(my_generator)
+'a'
+>>> my_generator.next()
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+AttributeError: 'generator' object has no attribute 'next'
+
+ + + +
+
+ +### In Python 3.x for-loop variables don't leak into the global namespace anymore + +[[back to Python 2.x vs 3.x overview](#py23_overview)] + +This goes back to a change that was made in Python 3.x and is described in [What’s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) as follows: + +"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." + +
+`[In:]` +
from platform import python_version
+print('This code cell was executed in Python', python_version())
+
+i = 1
+print([i for i in range(5)])
+print(i, '-> i in global')
+
+ +
+`[Out:]` +
This code cell was executed in Python 3.3.5
+[0, 1, 2, 3, 4]
+1 -> i in global
+
+ + +
+
+
+`[In:]` +
from platform import python_version
+print 'This code cell was executed in Python', python_version()
+
+i = 1
+print [i for i in range(5)]
+print i, '-> i in global' 
+
+ +
+`[Out:]` +
This code cell was executed in Python 2.7.6
+[0, 1, 2, 3, 4]
+4 -> i in global
+
+ + + +
+
+ +#### Python 3.x prevents us from comparing unorderable types + +[[back to Python 2.x vs 3.x overview](#py23_overview)] + +
+`[In:]` +
from platform import python_version
+print 'This code cell was executed in Python', python_version()
+
+print [1, 2] > 'foo'
+print (1, 2) > 'foo'
+print [1, 2] > (1, 2)
+
+ +
+`[Out:]` +
This code cell was executed in Python 2.7.6
+False
+True
+False
+
+ +
+
+
+ +`[In:]` +
from platform import python_version
+print('This code cell was executed in Python', python_version())
+
+print([1, 2] > 'foo')
+print((1, 2) > 'foo')
+print([1, 2] > (1, 2))
+
+ +`[Out:]` +
This code cell was executed in Python 3.3.5
+---------------------------------------------------------------------------
+TypeError                                 Traceback (most recent call last)
+<ipython-input-3-1d774c677f73> in <module>()
+      2 print('This code cell was executed in Python', python_version())
+      3 
+----> 4 [1, 2] > 'foo'
+      5 (1, 2) > 'foo'
+      6 [1, 2] > (1, 2)
+
+TypeError: unorderable types: list() > str()
+