{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[Sebastian Raschka](http://sebastianraschka.com) \n", "\n", "last updated 07/02/2016\n", "\n", "- [Open in IPython nbviewer](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/tutorials/key_differences_between_python_2_and_3.ipynb?create=1) \n", "\n", "- [Link to this IPython notebook on Github](https://github.com/rasbt/python_reference/blob/master/tutorials/key_differences_between_python_2_and_3.ipynb) \n", "\n", "- [Link to the GitHub repository python_reference](https://github.com/rasbt/python_reference)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "I would be happy to hear your comments and suggestions. \n", "Please feel free to drop me a note via\n", "[twitter](https://twitter.com/rasbt), [email](mailto:bluewoodtree@gmail.com), or [google+](https://plus.google.com/118404394130788869227).\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Key differences between Python 2.7.x and Python 3.x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "Many beginning Python users are wondering with which version of Python they should start. My answer to this question is usually something along the lines \"just go with the version your favorite tutorial was written in, and check out the differences later on.\"\n", "\n", "But what if you are starting a new project and have the choice to pick? I would say there is currently no \"right\" or \"wrong\" as long as both Python 2.7.x and Python 3.x support the libraries that you are planning to use. However, it is worthwhile to have a look at the major differences between those two most popular versions of Python to avoid common pitfalls when writing the code for either one of them, or if you are planning to port your project." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sections" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "- [Using the `__future__` module](#future_module)\n", "\n", "- [The print function](#The-print-function)\n", "\n", "- [Integer division](#Integer-division)\n", "\n", "- [Unicode](#Unicode)\n", "\n", "- [xrange](#xrange)\n", "\n", "- [Raising exceptions](#Raising-exceptions)\n", "\n", "- [Handling exceptions](#Handling-exceptions)\n", "\n", "- [The next() function and .next() method](#The-next-function-and-next-method)\n", "\n", "- [For-loop variables and the global namespace leak](#For-loop-variables-and-the-global-namespace-leak)\n", "\n", "- [Comparing unorderable types](#Comparing-unorderable-types)\n", "\n", "- [Parsing user inputs via input()](#Parsing-user-inputs-via-input)\n", "\n", "- [Returning iterable objects instead of lists](#Returning-iterable-objects-instead-of-lists)\n", "\n", "- [Banker's Rounding](#Banker's-Rounding)\n", "\n", "- [More articles about Python 2 and Python 3](#More-articles-about-Python-2-and-Python-3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The `__future__` module" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python 3.x introduced some Python 2-incompatible keywords and features that can be imported via the in-built `__future__` module in Python 2. It is recommended to use `__future__` imports it if you are planning Python 3.x support for your code. For example, if we want Python 3.x's integer division behavior in Python 2, we can import it via\n", "\n", " from __future__ import division\n", " \n", "More features that can be imported from the `__future__` module are listed in the table below:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
featureoptional inmandatory ineffect
nested_scopes2.1.0b12.2PEP 227:\n", "Statically Nested Scopes
generators2.2.0a12.3PEP 255:\n", "Simple Generators
division2.2.0a23.0PEP 238:\n", "Changing the Division Operator
absolute_import2.5.0a13.0PEP 328:\n", "Imports: Multi-Line and Absolute/Relative
with_statement2.5.0a12.6PEP 343:\n", "The “with” Statement
print_function2.6.0a23.0PEP 3105:\n", "Make print a function
unicode_literals2.6.0a23.0PEP 3112:\n", "Bytes literals in Python 3000
\n", "
\n", "
(Source: [https://docs.python.org/2/library/__future__.html](https://docs.python.org/2/library/__future__.html#module-__future__))
" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from platform import python_version" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The print function" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Very trivial, and the change in the print-syntax is probably the most widely known change, but still it is worth mentioning: Python 2's print statement has been replaced by the `print()` function, meaning that we have to wrap the object that we want to print in parantheses. \n", "\n", "Python 2 doesn't have a problem with additional parantheses, but in contrast, Python 3 would raise a `SyntaxError` if we called the print function the Python 2-way without the parentheses. \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n", "Hello, World!\n", "Hello, World!\n", "text print more text on the same line\n" ] } ], "source": [ "print 'Python', python_version()\n", "print 'Hello, World!'\n", "print('Hello, World!')\n", "print \"text\", ; print 'print more text on the same line'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n", "Hello, World!\n", "some text, print more text on the same line\n" ] } ], "source": [ "print('Python', python_version())\n", "print('Hello, World!')\n", "\n", "print(\"some text,\", end=\"\") \n", "print(' print more text on the same line')" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "ename": "SyntaxError", "evalue": "invalid syntax (, line 1)", "output_type": "error", "traceback": [ "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m print 'Hello, World!'\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" ] } ], "source": [ "print 'Hello, World!'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note:**\n", "\n", "Printing \"Hello, World\" above via Python 2 looked quite \"normal\". However, if we have multiple objects inside the parantheses, we will create a tuple, since `print` is a \"statement\" in Python 2, not a function call." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.7\n", "('a', 'b')\n", "a b\n" ] } ], "source": [ "print 'Python', python_version()\n", "print('a', 'b')\n", "print 'a', 'b'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Integer division" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This change is particularly dangerous if you are porting code, or if you are executing Python 3 code in Python 2, since the change in integer-division behavior can often go unnoticed (it doesn't raise a `SyntaxError`). \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 (and vice versa, I recommend a `from __future__ import division` in your Python 2 scripts)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n", "3 / 2 = 1\n", "3 // 2 = 1\n", "3 / 2.0 = 1.5\n", "3 // 2.0 = 1.0\n" ] } ], "source": [ "print 'Python', python_version()\n", "print '3 / 2 =', 3 / 2\n", "print '3 // 2 =', 3 // 2\n", "print '3 / 2.0 =', 3 / 2.0\n", "print '3 // 2.0 =', 3 // 2.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n", "3 / 2 = 1.5\n", "3 // 2 = 1\n", "3 / 2.0 = 1.5\n", "3 // 2.0 = 1.0\n" ] } ], "source": [ "print('Python', python_version())\n", "print('3 / 2 =', 3 / 2)\n", "print('3 // 2 =', 3 // 2)\n", "print('3 / 2.0 =', 3 / 2.0)\n", "print('3 // 2.0 =', 3 // 2.0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Unicode" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python 2 has ASCII `str()` types, separate `unicode()`, but no `byte` type. \n", "\n", "Now, in Python 3, we finally have Unicode (utf-8) `str`ings, and 2 byte classes: `byte` and `bytearray`s." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n" ] } ], "source": [ "print 'Python', python_version()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "print type(unicode('this is like a python3 str type'))" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "print type(b'byte type does not exist')" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "they are really the same\n" ] } ], "source": [ "print 'they are really' + b' the same'" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "print type(bytearray(b'bytearray oddly does exist though'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n", "strings are now utf-8 μnicoΔé!\n" ] } ], "source": [ "print('Python', python_version())\n", "print('strings are now utf-8 \\u03BCnico\\u0394é!')" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1 has \n" ] } ], "source": [ "print('Python', python_version(), end=\"\")\n", "print(' has', type(b' bytes for storing data'))" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "and Python 3.4.1 also has \n" ] } ], "source": [ "print('and Python', python_version(), end=\"\")\n", "print(' also has', type(bytearray(b'bytearrays')))" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "Can't convert 'bytes' object to str implicitly", "output_type": "error", "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[0;32m----> 1\u001b[0;31m \u001b[0;34m'note that we cannot add a string'\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;34mb'bytes for data'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: Can't convert 'bytes' object to str implicitly" ] } ], "source": [ "'note that we cannot add a string' + b'bytes for data'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## xrange" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " \n", "The usage of `xrange()` is very popular in Python 2.x for creating an iterable object, e.g., in a for-loop or list/set-dictionary-comprehension. \n", "The behavior was quite similar to a generator (i.e., \"lazy evaluation\"), but here the xrange-iterable is not exhaustible - meaning, you could iterate over it infinitely. \n", "\n", "\n", "Thanks to its \"lazy-evaluation\", the advantage of the regular `range()` is that `xrange()` is generally faster if you have to iterate over it only once (e.g., in a for-loop). However, in contrast to 1-time iterations, it is not recommended if you repeat the iteration multiple times, since the generation happens every time from scratch! \n", "\n", "In Python 3, the `range()` was implemented like the `xrange()` function so that a dedicated `xrange()` function does not exist anymore (`xrange()` raises a `NameError` in Python 3)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import timeit\n", "\n", "n = 10000\n", "def test_range(n):\n", " return for i in range(n):\n", " pass\n", " \n", "def test_xrange(n):\n", " for i in xrange(n):\n", " pass " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n", "\n", "timing range()\n", "1000 loops, best of 3: 433 µs per loop\n", "\n", "\n", "timing xrange()\n", "1000 loops, best of 3: 350 µs per loop\n" ] } ], "source": [ "print 'Python', python_version()\n", "\n", "print '\\ntiming range()'\n", "%timeit test_range(n)\n", "\n", "print '\\n\\ntiming xrange()'\n", "%timeit test_xrange(n)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n", "\n", "timing range()\n", "1000 loops, best of 3: 520 µs per loop\n" ] } ], "source": [ "print('Python', python_version())\n", "\n", "print('\\ntiming range()')\n", "%timeit test_range(n)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "ename": "NameError", "evalue": "name 'xrange' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mNameError\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[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mxrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'xrange' is not defined" ] } ], "source": [ "print(xrange(10))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "
\n", "
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The `__contains__` method for `range` objects in Python 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another thing worth mentioning is that `range` got a \"new\" `__contains__` method in Python 3.x (thanks to [Yuchen Ying](https://github.com/yegle), who pointed this out). The `__contains__` method can speedup \"look-ups\" in Python 3.x `range` significantly for integer and Boolean types.\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [], "source": [ "x = 10000000" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def val_in_range(x, val):\n", " return val in range(x)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def val_in_xrange(x, val):\n", " return val in xrange(x)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n", "1 loops, best of 3: 742 ms per loop\n", "1000000 loops, best of 3: 1.19 µs per loop\n" ] } ], "source": [ "print('Python', python_version())\n", "assert(val_in_range(x, x/2) == True)\n", "assert(val_in_range(x, x//2) == True)\n", "%timeit val_in_range(x, x/2)\n", "%timeit val_in_range(x, x//2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Based on the `timeit` results above, you see that the execution for the \"look up\" was about 60,000 faster when it was of an integer type rather than a float. However, since Python 2.x's `range` or `xrange` doesn't have a `__contains__` method, the \"look-up speed\" wouldn't be that much different for integers or floats:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.7\n", "1 loops, best of 3: 285 ms per loop\n", "1 loops, best of 3: 179 ms per loop\n", "1 loops, best of 3: 658 ms per loop\n", "1 loops, best of 3: 556 ms per loop\n" ] } ], "source": [ "print 'Python', python_version()\n", "assert(val_in_xrange(x, x/2.0) == True)\n", "assert(val_in_xrange(x, x/2) == True)\n", "assert(val_in_range(x, x/2) == True)\n", "assert(val_in_range(x, x//2) == True)\n", "%timeit val_in_xrange(x, x/2.0)\n", "%timeit val_in_xrange(x, x/2)\n", "%timeit val_in_range(x, x/2.0)\n", "%timeit val_in_range(x, x/2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Below the \"proofs\" that the `__contain__` method wasn't added to Python 2.x yet:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print('Python', python_version())\n", "range.__contains__" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.7\n" ] }, { "ename": "AttributeError", "evalue": "'builtin_function_or_method' object has no attribute '__contains__'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mAttributeError\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[0;32mprint\u001b[0m \u001b[0;34m'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[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mrange\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__contains__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'builtin_function_or_method' object has no attribute '__contains__'" ] } ], "source": [ "print 'Python', python_version()\n", "range.__contains__" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.7\n" ] }, { "ename": "AttributeError", "evalue": "type object 'xrange' has no attribute '__contains__'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mAttributeError\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[0;32mprint\u001b[0m \u001b[0;34m'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[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mxrange\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__contains__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: type object 'xrange' has no attribute '__contains__'" ] } ], "source": [ "print 'Python', python_version()\n", "xrange.__contains__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Note about the speed differences in Python 2 and 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some people pointed out the speed difference between Python 3's `range()` and Python2's `xrange()`. Since they are implemented the same way one would expect the same speed. However the difference here just comes from the fact that Python 3 generally tends to run slower than Python 2. " ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def test_while():\n", " i = 0\n", " while i < 20000:\n", " i += 1\n", " return" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n", "100 loops, best of 3: 2.68 ms per loop\n" ] } ], "source": [ "print('Python', python_version())\n", "%timeit test_while()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n", "1000 loops, best of 3: 1.72 ms per loop\n" ] } ], "source": [ "print 'Python', python_version()\n", "%timeit test_while()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Raising exceptions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "Where Python 2 accepts both notations, the 'old' and the 'new' syntax, Python 3 chokes (and raises a `SyntaxError` in turn) if we don't enclose the exception argument in parentheses:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n" ] } ], "source": [ "print 'Python', python_version()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "ename": "IOError", "evalue": "file error", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mIOError\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[0;32mraise\u001b[0m \u001b[0mIOError\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"file error\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mIOError\u001b[0m: file error" ] } ], "source": [ "raise IOError, \"file error\"" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "ename": "IOError", "evalue": "file error", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mIOError\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[0;32mraise\u001b[0m \u001b[0mIOError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"file error\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mIOError\u001b[0m: file error" ] } ], "source": [ "raise IOError(\"file error\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n" ] } ], "source": [ "print('Python', python_version())" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "ename": "SyntaxError", "evalue": "invalid syntax (, line 1)", "output_type": "error", "traceback": [ "\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m raise IOError, \"file error\"\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n" ] } ], "source": [ "raise IOError, \"file error\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The proper way to raise an exception in Python 3:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n" ] }, { "ename": "OSError", "evalue": "file error", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mOSError\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'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[0;32m----> 2\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mIOError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"file error\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mOSError\u001b[0m: file error" ] } ], "source": [ "print('Python', python_version())\n", "raise IOError(\"file error\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Handling exceptions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also the handling of exceptions has slightly changed in Python 3. In Python 3 we have to use the \"`as`\" keyword now" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n", "name 'let_us_cause_a_NameError' is not defined --> our error message\n" ] } ], "source": [ "print 'Python', python_version()\n", "try:\n", " let_us_cause_a_NameError\n", "except NameError, err:\n", " print err, '--> our error message'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n", "name 'let_us_cause_a_NameError' is not defined --> our error message\n" ] } ], "source": [ "print('Python', python_version())\n", "try:\n", " let_us_cause_a_NameError\n", "except NameError as err:\n", " print(err, '--> our error message')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The next() function and .next() method" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since `next()` (`.next()`) is such a commonly used function (method), this is another syntax change (or rather change in implementation) that is worth mentioning: where you can use both the function and method syntax in Python 2.7.5, the `next()` function is all that remains in Python 3 (calling the `.next()` method raises an `AttributeError`)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n" ] }, { "data": { "text/plain": [ "'b'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print 'Python', python_version()\n", "\n", "my_generator = (letter for letter in 'abcdefg')\n", "\n", "next(my_generator)\n", "my_generator.next()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n" ] }, { "data": { "text/plain": [ "'a'" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "print('Python', python_version())\n", "\n", "my_generator = (letter for letter in 'abcdefg')\n", "\n", "next(my_generator)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "ename": "AttributeError", "evalue": "'generator' object has no attribute 'next'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mAttributeError\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[0mmy_generator\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'generator' object has no attribute 'next'" ] } ], "source": [ "my_generator.next()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## For-loop variables and the global namespace leak" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Good news is: In Python 3.x for-loop variables don't leak into the global namespace anymore!\n", "\n", "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:\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.\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n", "before: i = 1\n", "comprehension: [0, 1, 2, 3, 4]\n", "after: i = 4\n" ] } ], "source": [ "print 'Python', python_version()\n", "\n", "i = 1\n", "print 'before: i =', i\n", "\n", "print 'comprehension: ', [i for i in range(5)]\n", "\n", "print 'after: i =', i" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n", "before: i = 1\n", "comprehension: [0, 1, 2, 3, 4]\n", "after: i = 1\n" ] } ], "source": [ "print('Python', python_version())\n", "\n", "i = 1\n", "print('before: i =', i)\n", "\n", "print('comprehension:', [i for i in range(5)])\n", "\n", "print('after: i =', i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comparing unorderable types" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another nice change in Python 3 is that a `TypeError` is raised as warning if we try to compare unorderable types." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n", "[1, 2] > 'foo' = False\n", "(1, 2) > 'foo' = True\n", "[1, 2] > (1, 2) = False\n" ] } ], "source": [ "print 'Python', python_version()\n", "print \"[1, 2] > 'foo' = \", [1, 2] > 'foo'\n", "print \"(1, 2) > 'foo' = \", (1, 2) > 'foo'\n", "print \"[1, 2] > (1, 2) = \", [1, 2] > (1, 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n" ] }, { "ename": "TypeError", "evalue": "unorderable types: list() > str()", "output_type": "error", "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 1\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'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[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"[1, 2] > 'foo' = \"\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[0;34m'foo'\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[0;34m\"(1, 2) > 'foo' = \"\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[0;34m'foo'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"[1, 2] > (1, 2) = \"\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[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[0m\n", "\u001b[0;31mTypeError\u001b[0m: unorderable types: list() > str()" ] } ], "source": [ "print('Python', python_version())\n", "print(\"[1, 2] > 'foo' = \", [1, 2] > 'foo')\n", "print(\"(1, 2) > 'foo' = \", (1, 2) > 'foo')\n", "print(\"[1, 2] > (1, 2) = \", [1, 2] > (1, 2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Parsing user inputs via input()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fortunately, the `input()` function was fixed in Python 3 so that it always stores the user inputs as `str` objects. In order to avoid the dangerous behavior in Python 2 to read in other types than `strings`, we have to use `raw_input()` instead." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Python 2.7.6 \n",
    "[GCC 4.0.1 (Apple Inc. build 5493)] on darwin\n",
    "Type "help", "copyright", "credits" or "license" for more information.\n",
    "\n",
    ">>> my_input = input('enter a number: ')\n",
    "\n",
    "enter a number: 123\n",
    "\n",
    ">>> type(my_input)\n",
    "<type 'int'>\n",
    "\n",
    ">>> my_input = raw_input('enter a number: ')\n",
    "\n",
    "enter a number: 123\n",
    "\n",
    ">>> type(my_input)\n",
    "<type 'str'>\n",
    "
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Python 3.4.1 \n",
    "[GCC 4.2.1 (Apple Inc. build 5577)] on darwin\n",
    "Type "help", "copyright", "credits" or "license" for more information.\n",
    "\n",
    ">>> my_input = input('enter a number: ')\n",
    "\n",
    "enter a number: 123\n",
    "\n",
    ">>> type(my_input)\n",
    "<class 'str'>\n",
    "
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Returning iterable objects instead of lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we have already seen in the [`xrange`](#xrange) section, some functions and methods return iterable objects in Python 3 now - instead of lists in Python 2. \n", "\n", "Since we usually iterate over those only once anyway, I think this change makes a lot of sense to save memory. However, it is also possible - in contrast to generators - to iterate over those multiple times if needed, it is aonly not so efficient.\n", "\n", "And for those cases where we really need the `list`-objects, we can simply convert the iterable object into a `list` via the `list()` function." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.6\n", "[0, 1, 2]\n", "\n" ] } ], "source": [ "print 'Python', python_version() \n", "\n", "print range(3) \n", "print type(range(3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.4.1\n", "range(0, 3)\n", "\n", "[0, 1, 2]\n" ] } ], "source": [ "print('Python', python_version())\n", "\n", "print(range(3))\n", "print(type(range(3)))\n", "print(list(range(3)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Some more commonly used functions and methods that don't return lists anymore in Python 3:**\n", "\n", "- `zip()`\n", "\n", "- `map()`\n", "\n", "- `filter()`\n", "\n", "- dictionary's `.keys()` method\n", "\n", "- dictionary's `.values()` method\n", "\n", "- dictionary's `.items()` method\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Banker's Rounding" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python 3 adopted the now standard way of rounding decimals when it results in a tie (.5) at the last significant digits. Now, in Python 3, decimals are rounded to the nearest even number. Although it's an inconvenience for code portability, it's supposedly a better way of rounding compared to rounding up as it avoids the bias towards large numbers. For more information, see the excellent Wikipedia articles and paragraphs:\n", "- [https://en.wikipedia.org/wiki/Rounding#Round_half_to_even](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even)\n", "- [https://en.wikipedia.org/wiki/IEEE_floating_point#Roundings_to_nearest](https://en.wikipedia.org/wiki/IEEE_floating_point#Roundings_to_nearest)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 2" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 2.7.12\n" ] } ], "source": [ "print 'Python', python_version()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "16.0" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "round(15.5)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "17.0" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "round(16.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Python 3" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python 3.5.1\n" ] } ], "source": [ "print('Python', python_version())" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "16" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "round(15.5)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "16" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "round(16.5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## More articles about Python 2 and Python 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to the section-overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is a list of some good articles concerning Python 2 and 3 that I would recommend as a follow-up.\n", "\n", "\n", "**// Porting to Python 3** \n", "\n", "- [Should I use Python 2 or Python 3 for my development activity?](https://wiki.python.org/moin/Python2orPython3)\n", "\n", "- [What’s New In Python 3.0](https://docs.python.org/3.0/whatsnew/3.0.html)\n", "\n", "- [Porting to Python 3](http://python3porting.com/differences.html)\n", "\n", "- [Porting Python 2 Code to Python 3](https://docs.python.org/3/howto/pyporting.html) \n", "\n", "- [How keep Python 3 moving forward](http://nothingbutsnark.svbtle.com/my-view-on-the-current-state-of-python-3)\n", "\n", "**// Pro and anti Python 3**\n", "\n", "- [10 awesome features of Python that you can't use because you refuse to upgrade to Python 3](http://asmeurer.github.io/python3-presentation/slides.html#1)\n", "\n", "- [Everything you did not want to know about Unicode in Python 3](http://lucumr.pocoo.org/2014/5/12/everything-about-unicode/)\n", "\n", "- [Python 3 is killing Python](https://medium.com/@deliciousrobots/5d2ad703365d/)\n", "\n", "- [Python 3 can revive Python](https://medium.com/p/2a7af4788b10)\n", "\n", "- [Python 3 is fine](http://sealedabstract.com/rants/python-3-is-fine/)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.12" } }, "nbformat": 4, "nbformat_minor": 0 }