diff options
Diffstat (limited to 'FOSS/Python/Dependencies/future-0.18.2/docs/notebooks/Writing Python 2-3 compatible code.ipynb')
| -rw-r--r-- | FOSS/Python/Dependencies/future-0.18.2/docs/notebooks/Writing Python 2-3 compatible code.ipynb | 3167 |
1 files changed, 3167 insertions, 0 deletions
diff --git a/FOSS/Python/Dependencies/future-0.18.2/docs/notebooks/Writing Python 2-3 compatible code.ipynb b/FOSS/Python/Dependencies/future-0.18.2/docs/notebooks/Writing Python 2-3 compatible code.ipynb new file mode 100644 index 0000000..0f585d2 --- /dev/null +++ b/FOSS/Python/Dependencies/future-0.18.2/docs/notebooks/Writing Python 2-3 compatible code.ipynb @@ -0,0 +1,3167 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Cheat Sheet: Writing Python 2-3 compatible code" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- **Copyright (c):** 2013-2019 Python Charmers Pty Ltd, Australia.\n", + "- **Author:** Ed Schofield.\n", + "- **Licence:** Creative Commons Attribution.\n", + "\n", + "A PDF version is here: http://python-future.org/compatible_idioms.pdf\n", + "\n", + "This notebook shows you idioms for writing future-proof code that is compatible with both versions of Python: 2 and 3. It accompanies Ed Schofield's talk at PyCon AU 2014, \"Writing 2/3 compatible code\". (The video is here: <http://www.youtube.com/watch?v=KOqk8j11aAI&t=10m14s>.)\n", + "\n", + "Minimum versions:\n", + "\n", + " - Python 2: 2.6+\n", + " - Python 3: 3.3+" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The imports below refer to these ``pip``-installable packages on PyPI:\n", + "\n", + " import future # pip install future\n", + " import builtins # pip install future\n", + " import past # pip install future\n", + " import six # pip install six\n", + "\n", + "The following scripts are also ``pip``-installable:\n", + "\n", + " futurize # pip install future\n", + " pasteurize # pip install future\n", + "\n", + "See http://python-future.org and https://pythonhosted.org/six/ for more information." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Essential syntax differences" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### print" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "print 'Hello'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "print('Hello')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To print multiple strings, import ``print_function`` to prevent Py2 from interpreting it as a tuple:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "print 'Hello', 'Guido'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from __future__ import print_function # (at top of module)\n", + "\n", + "print('Hello', 'Guido')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "print >> sys.stderr, 'Hello'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from __future__ import print_function\n", + "\n", + "print('Hello', file=sys.stderr)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "print 'Hello'," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from __future__ import print_function\n", + "\n", + "print('Hello', end='')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Raising exceptions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "raise ValueError, \"dodgy value\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "raise ValueError(\"dodgy value\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Raising exceptions with a traceback:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "traceback = sys.exc_info()[2]\n", + "raise ValueError, \"dodgy value\", traceback" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only:\n", + "raise ValueError(\"dodgy value\").with_traceback()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 1\n", + "from six import reraise as raise_\n", + "# or\n", + "from future.utils import raise_\n", + "\n", + "traceback = sys.exc_info()[2]\n", + "raise_(ValueError, \"dodgy value\", traceback)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 2\n", + "from future.utils import raise_with_traceback\n", + "\n", + "raise_with_traceback(ValueError(\"dodgy value\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Exception chaining (PEP 3134):" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Setup:\n", + "class DatabaseError(Exception):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only\n", + "class FileDatabase:\n", + " def __init__(self, filename):\n", + " try:\n", + " self.file = open(filename)\n", + " except IOError as exc:\n", + " raise DatabaseError('failed to open') from exc" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from future.utils import raise_from\n", + "\n", + "class FileDatabase:\n", + " def __init__(self, filename):\n", + " try:\n", + " self.file = open(filename)\n", + " except IOError as exc:\n", + " raise_from(DatabaseError('failed to open'), exc)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Testing the above:\n", + "try:\n", + " fd = FileDatabase('non_existent_file.txt')\n", + "except Exception as e:\n", + " assert isinstance(e.__cause__, IOError) # FileNotFoundError on Py3.3+ inherits from IOError" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Catching exceptions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "try:\n", + " ...\n", + "except ValueError, e:\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "try:\n", + " ...\n", + "except ValueError as e:\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Division" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Integer division (rounding down):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "assert 2 / 3 == 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "assert 2 // 3 == 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"True division\" (float division):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only:\n", + "assert 3 / 2 == 1.5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from __future__ import division # (at top of module)\n", + "\n", + "assert 3 / 2 == 1.5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Old division\" (i.e. compatible with Py2 behaviour):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "a = b / c # with any types" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from past.utils import old_div\n", + "\n", + "a = old_div(b, c) # always same as / on Py2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Long integers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Short integers are gone in Python 3 and ``long`` has become ``int`` (without the trailing ``L`` in the ``repr``)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "k = 9223372036854775808L\n", + "\n", + "# Python 2 and 3:\n", + "k = 9223372036854775808" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "bigint = 1L\n", + "\n", + "# Python 2 and 3\n", + "from builtins import int\n", + "bigint = int(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To test whether a value is an integer (of any kind):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "if isinstance(x, (int, long)):\n", + " ...\n", + "\n", + "# Python 3 only:\n", + "if isinstance(x, int):\n", + " ...\n", + "\n", + "# Python 2 and 3: option 1\n", + "from builtins import int # subclass of long on Py2\n", + "\n", + "if isinstance(x, int): # matches both int and long on Py2\n", + " ...\n", + "\n", + "# Python 2 and 3: option 2\n", + "from past.builtins import long\n", + "\n", + "if isinstance(x, (int, long)):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Octal constants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "0644 # Python 2 only" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "0o644 # Python 2 and 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Backtick repr" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "`x` # Python 2 only" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "repr(x) # Python 2 and 3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Metaclasses" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "class BaseForm(object):\n", + " pass\n", + "\n", + "class FormType(type):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "class Form(BaseForm):\n", + " __metaclass__ = FormType\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only:\n", + "class Form(BaseForm, metaclass=FormType):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from six import with_metaclass\n", + "# or\n", + "from future.utils import with_metaclass\n", + "\n", + "class Form(with_metaclass(FormType, BaseForm)):\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Strings and bytes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Unicode (text) string literals" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you are upgrading an existing Python 2 codebase, it may be preferable to mark up all string literals as unicode explicitly with ``u`` prefixes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "s1 = 'The Zen of Python'\n", + "s2 = u'きたないのよりきれいな方がいい\\n'\n", + "\n", + "# Python 2 and 3\n", + "s1 = u'The Zen of Python'\n", + "s2 = u'きたないのよりきれいな方がいい\\n'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ``futurize`` and ``python-modernize`` tools do not currently offer an option to do this automatically." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you are writing code for a new project or new codebase, you can use this idiom to make all string literals in a module unicode strings:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3\n", + "from __future__ import unicode_literals # at top of module\n", + "\n", + "s1 = 'The Zen of Python'\n", + "s2 = 'きたないのよりきれいな方がいい\\n'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "See http://python-future.org/unicode_literals.html for more discussion on which style to use." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Byte-string literals" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "s = 'This must be a byte-string'\n", + "\n", + "# Python 2 and 3\n", + "s = b'This must be a byte-string'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To loop over a byte-string with possible high-bit characters, obtaining each character as a byte-string of length 1:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "for bytechar in 'byte-string with high-bit chars like \\xf9':\n", + " ...\n", + "\n", + "# Python 3 only:\n", + "for myint in b'byte-string with high-bit chars like \\xf9':\n", + " bytechar = bytes([myint])\n", + "\n", + "# Python 2 and 3:\n", + "from builtins import bytes\n", + "for myint in bytes(b'byte-string with high-bit chars like \\xf9'):\n", + " bytechar = bytes([myint])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As an alternative, ``chr()`` and ``.encode('latin-1')`` can be used to convert an int into a 1-char byte string:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only:\n", + "for myint in b'byte-string with high-bit chars like \\xf9':\n", + " char = chr(myint) # returns a unicode string\n", + " bytechar = char.encode('latin-1')\n", + "\n", + "# Python 2 and 3:\n", + "from builtins import bytes, chr\n", + "for myint in bytes(b'byte-string with high-bit chars like \\xf9'):\n", + " char = chr(myint) # returns a unicode string\n", + " bytechar = char.encode('latin-1') # forces returning a byte str" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### basestring" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "a = u'abc'\n", + "b = 'def'\n", + "assert (isinstance(a, basestring) and isinstance(b, basestring))\n", + "\n", + "# Python 2 and 3: alternative 1\n", + "from past.builtins import basestring # pip install future\n", + "\n", + "a = u'abc'\n", + "b = b'def'\n", + "assert (isinstance(a, basestring) and isinstance(b, basestring))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 2: refactor the code to avoid considering\n", + "# byte-strings as strings.\n", + "\n", + "from builtins import str\n", + "a = u'abc'\n", + "b = b'def'\n", + "c = b.decode()\n", + "assert isinstance(a, str) and isinstance(c, str)\n", + "# ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### unicode" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "templates = [u\"blog/blog_post_detail_%s.html\" % unicode(slug)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 1\n", + "from builtins import str\n", + "templates = [u\"blog/blog_post_detail_%s.html\" % str(slug)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 2\n", + "from builtins import str as text\n", + "templates = [u\"blog/blog_post_detail_%s.html\" % text(slug)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### StringIO" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "from StringIO import StringIO\n", + "# or:\n", + "from cStringIO import StringIO\n", + "\n", + "# Python 2 and 3:\n", + "from io import BytesIO # for handling byte strings\n", + "from io import StringIO # for handling unicode strings" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports relative to a package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Suppose the package is:\n", + "\n", + " mypackage/\n", + " __init__.py\n", + " submodule1.py\n", + " submodule2.py\n", + " \n", + "and the code below is in ``submodule1.py``:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only: \n", + "import submodule2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from . import submodule2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "# To make Py2 code safer (more like Py3) by preventing\n", + "# implicit relative imports, you can also add this to the top:\n", + "from __future__ import absolute_import" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dictionaries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "heights = {'Fred': 175, 'Anne': 166, 'Joe': 192}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Iterating through ``dict`` keys/values/items" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Iterable dict keys:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "for key in heights.iterkeys():\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "for key in heights:\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Iterable dict values:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "for value in heights.itervalues():\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Idiomatic Python 3\n", + "for value in heights.values(): # extra memory overhead on Py2\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 1\n", + "from builtins import dict\n", + "\n", + "heights = dict(Fred=175, Anne=166, Joe=192)\n", + "for key in heights.values(): # efficient on Py2 and Py3\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 2\n", + "from future.utils import itervalues\n", + "# or\n", + "from six import itervalues\n", + "\n", + "for key in itervalues(heights):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Iterable dict items:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "for (key, value) in heights.iteritems():\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 1\n", + "for (key, value) in heights.items(): # inefficient on Py2 \n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 2\n", + "from future.utils import viewitems\n", + "\n", + "for (key, value) in viewitems(heights): # also behaves like a set\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 3\n", + "from future.utils import iteritems\n", + "# or\n", + "from six import iteritems\n", + "\n", + "for (key, value) in iteritems(heights):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### dict keys/values/items as a list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "dict keys as a list:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "keylist = heights.keys()\n", + "assert isinstance(keylist, list)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "keylist = list(heights)\n", + "assert isinstance(keylist, list)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "dict values as a list:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "heights = {'Fred': 175, 'Anne': 166, 'Joe': 192}\n", + "valuelist = heights.values()\n", + "assert isinstance(valuelist, list)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 1\n", + "valuelist = list(heights.values()) # inefficient on Py2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 2\n", + "from builtins import dict\n", + "\n", + "heights = dict(Fred=175, Anne=166, Joe=192)\n", + "valuelist = list(heights.values())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 3\n", + "from future.utils import listvalues\n", + "\n", + "valuelist = listvalues(heights)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 4\n", + "from future.utils import itervalues\n", + "# or\n", + "from six import itervalues\n", + "\n", + "valuelist = list(itervalues(heights))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "dict items as a list:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 1\n", + "itemlist = list(heights.items()) # inefficient on Py2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 2\n", + "from future.utils import listitems\n", + "\n", + "itemlist = listitems(heights)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 3\n", + "from future.utils import iteritems\n", + "# or\n", + "from six import iteritems\n", + "\n", + "itemlist = list(iteritems(heights))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Custom class behaviour" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom iterators" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "class Upper(object):\n", + " def __init__(self, iterable):\n", + " self._iter = iter(iterable)\n", + " def next(self): # Py2-style\n", + " return self._iter.next().upper()\n", + " def __iter__(self):\n", + " return self\n", + "\n", + "itr = Upper('hello')\n", + "assert itr.next() == 'H' # Py2-style\n", + "assert list(itr) == list('ELLO')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 1\n", + "from builtins import object\n", + "\n", + "class Upper(object):\n", + " def __init__(self, iterable):\n", + " self._iter = iter(iterable)\n", + " def __next__(self): # Py3-style iterator interface\n", + " return next(self._iter).upper() # builtin next() function calls\n", + " def __iter__(self):\n", + " return self\n", + "\n", + "itr = Upper('hello')\n", + "assert next(itr) == 'H' # compatible style\n", + "assert list(itr) == list('ELLO')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 2\n", + "from future.utils import implements_iterator\n", + "\n", + "@implements_iterator\n", + "class Upper(object):\n", + " def __init__(self, iterable):\n", + " self._iter = iter(iterable)\n", + " def __next__(self): # Py3-style iterator interface\n", + " return next(self._iter).upper() # builtin next() function calls\n", + " def __iter__(self):\n", + " return self\n", + "\n", + "itr = Upper('hello')\n", + "assert next(itr) == 'H'\n", + "assert list(itr) == list('ELLO')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom ``__str__`` methods" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "class MyClass(object):\n", + " def __unicode__(self):\n", + " return 'Unicode string: \\u5b54\\u5b50'\n", + " def __str__(self):\n", + " return unicode(self).encode('utf-8')\n", + "\n", + "a = MyClass()\n", + "print(a) # prints encoded string" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Unicode string: 孔子\n" + ] + } + ], + "source": [ + "# Python 2 and 3:\n", + "from future.utils import python_2_unicode_compatible\n", + "\n", + "@python_2_unicode_compatible\n", + "class MyClass(object):\n", + " def __str__(self):\n", + " return u'Unicode string: \\u5b54\\u5b50'\n", + "\n", + "a = MyClass()\n", + "print(a) # prints string encoded as utf-8 on Py2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom ``__nonzero__`` vs ``__bool__`` method:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "class AllOrNothing(object):\n", + " def __init__(self, l):\n", + " self.l = l\n", + " def __nonzero__(self):\n", + " return all(self.l)\n", + "\n", + "container = AllOrNothing([0, 100, 200])\n", + "assert not bool(container)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from builtins import object\n", + "\n", + "class AllOrNothing(object):\n", + " def __init__(self, l):\n", + " self.l = l\n", + " def __bool__(self):\n", + " return all(self.l)\n", + "\n", + "container = AllOrNothing([0, 100, 200])\n", + "assert not bool(container)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lists versus iterators" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### xrange" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "for i in xrange(10**8):\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: forward-compatible\n", + "from builtins import range\n", + "for i in range(10**8):\n", + " ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: backward-compatible\n", + "from past.builtins import xrange\n", + "for i in xrange(10**8):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### range" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "mylist = range(5)\n", + "assert mylist == [0, 1, 2, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: forward-compatible: option 1\n", + "mylist = list(range(5)) # copies memory on Py2\n", + "assert mylist == [0, 1, 2, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: forward-compatible: option 2\n", + "from builtins import range\n", + "\n", + "mylist = list(range(5))\n", + "assert mylist == [0, 1, 2, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 3\n", + "from future.utils import lrange\n", + "\n", + "mylist = lrange(5)\n", + "assert mylist == [0, 1, 2, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: backward compatible\n", + "from past.builtins import range\n", + "\n", + "mylist = range(5)\n", + "assert mylist == [0, 1, 2, 3, 4]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### map" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "mynewlist = map(f, myoldlist)\n", + "assert mynewlist == [f(x) for x in myoldlist]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 1\n", + "# Idiomatic Py3, but inefficient on Py2\n", + "mynewlist = list(map(f, myoldlist))\n", + "assert mynewlist == [f(x) for x in myoldlist]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 2\n", + "from builtins import map\n", + "\n", + "mynewlist = list(map(f, myoldlist))\n", + "assert mynewlist == [f(x) for x in myoldlist]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 3\n", + "try:\n", + " from itertools import imap as map\n", + "except ImportError:\n", + " pass\n", + "\n", + "mynewlist = list(map(f, myoldlist)) # inefficient on Py2\n", + "assert mynewlist == [f(x) for x in myoldlist]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 4\n", + "from future.utils import lmap\n", + "\n", + "mynewlist = lmap(f, myoldlist)\n", + "assert mynewlist == [f(x) for x in myoldlist]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 5\n", + "from past.builtins import map\n", + "\n", + "mynewlist = map(f, myoldlist)\n", + "assert mynewlist == [f(x) for x in myoldlist]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### imap" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "from itertools import imap\n", + "\n", + "myiter = imap(func, myoldlist)\n", + "assert isinstance(myiter, iter)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only:\n", + "myiter = map(func, myoldlist)\n", + "assert isinstance(myiter, iter)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 1\n", + "from builtins import map\n", + "\n", + "myiter = map(func, myoldlist)\n", + "assert isinstance(myiter, iter)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 2\n", + "try:\n", + " from itertools import imap as map\n", + "except ImportError:\n", + " pass\n", + "\n", + "myiter = map(func, myoldlist)\n", + "assert isinstance(myiter, iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### zip, izip" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As above with ``zip`` and ``itertools.izip``." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### filter, ifilter" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As above with ``filter`` and ``itertools.ifilter`` too." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Other builtins" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### File IO with open()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "f = open('myfile.txt')\n", + "data = f.read() # as a byte string\n", + "text = data.decode('utf-8')\n", + "\n", + "# Python 2 and 3: alternative 1\n", + "from io import open\n", + "f = open('myfile.txt', 'rb')\n", + "data = f.read() # as bytes\n", + "text = data.decode('utf-8') # unicode, not bytes\n", + "\n", + "# Python 2 and 3: alternative 2\n", + "from io import open\n", + "f = open('myfile.txt', encoding='utf-8')\n", + "text = f.read() # unicode, not bytes" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### reduce()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from functools import reduce\n", + "\n", + "assert reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) == 1+2+3+4+5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### raw_input()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "name = raw_input('What is your name? ')\n", + "assert isinstance(name, str) # native str" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from builtins import input\n", + "\n", + "name = input('What is your name? ')\n", + "assert isinstance(name, str) # native str on Py2 and Py3" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### input()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "input(\"Type something safe please: \")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3\n", + "from builtins import input\n", + "eval(input(\"Type something safe please: \"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Warning: using either of these is **unsafe** with untrusted input." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### file()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "f = file(pathname)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "f = open(pathname)\n", + "\n", + "# But preferably, use this:\n", + "from io import open\n", + "f = open(pathname, 'rb') # if f.read() should return bytes\n", + "# or\n", + "f = open(pathname, 'rt') # if f.read() should return unicode text" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### exec" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "exec 'x = 10'\n", + "\n", + "# Python 2 and 3:\n", + "exec('x = 10')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "g = globals()\n", + "exec 'x = 10' in g\n", + "\n", + "# Python 2 and 3:\n", + "g = globals()\n", + "exec('x = 10', g)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "l = locals()\n", + "exec 'x = 10' in g, l\n", + "\n", + "# Python 2 and 3:\n", + "exec('x = 10', g, l)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But note that Py3's `exec()` is less powerful (and less dangerous) than Py2's `exec` statement." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### execfile()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "execfile('myfile.py')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 1\n", + "from past.builtins import execfile\n", + "\n", + "execfile('myfile.py')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 2\n", + "exec(compile(open('myfile.py').read()))\n", + "\n", + "# This can sometimes cause this:\n", + "# SyntaxError: function ... uses import * and bare exec ...\n", + "# See https://github.com/PythonCharmers/python-future/issues/37" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### unichr()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "assert unichr(8364) == '€'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only:\n", + "assert chr(8364) == '€'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from builtins import chr\n", + "assert chr(8364) == '€'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### intern()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "intern('mystring')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only:\n", + "from sys import intern\n", + "intern('mystring')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 1\n", + "from past.builtins import intern\n", + "intern('mystring')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 2\n", + "from six.moves import intern\n", + "intern('mystring')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 3\n", + "from future.standard_library import install_aliases\n", + "install_aliases()\n", + "from sys import intern\n", + "intern('mystring')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 2\n", + "try:\n", + " from sys import intern\n", + "except ImportError:\n", + " pass\n", + "intern('mystring')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### apply()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "args = ('a', 'b')\n", + "kwargs = {'kwarg1': True}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "apply(f, args, kwargs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 1\n", + "f(*args, **kwargs)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 2\n", + "from past.builtins import apply\n", + "apply(f, args, kwargs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### chr()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "assert chr(64) == b'@'\n", + "assert chr(200) == b'\\xc8'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only: option 1\n", + "assert chr(64).encode('latin-1') == b'@'\n", + "assert chr(0xc8).encode('latin-1') == b'\\xc8'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 1\n", + "from builtins import chr\n", + "\n", + "assert chr(64).encode('latin-1') == b'@'\n", + "assert chr(0xc8).encode('latin-1') == b'\\xc8'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only: option 2\n", + "assert bytes([64]) == b'@'\n", + "assert bytes([0xc8]) == b'\\xc8'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: option 2\n", + "from builtins import bytes\n", + "\n", + "assert bytes([64]) == b'@'\n", + "assert bytes([0xc8]) == b'\\xc8'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### cmp()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 1\n", + "from past.builtins import cmp\n", + "assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 2\n", + "cmp = lambda(x, y): (x > y) - (x < y)\n", + "assert cmp('a', 'b') < 0 and cmp('b', 'a') > 0 and cmp('c', 'c') == 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### reload()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "reload(mymodule)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3\n", + "from imp import reload\n", + "reload(mymodule)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Standard library" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### dbm modules" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "import anydbm\n", + "import whichdb\n", + "import dbm\n", + "import dumbdbm\n", + "import gdbm\n", + "\n", + "# Python 2 and 3: alternative 1\n", + "from future import standard_library\n", + "standard_library.install_aliases()\n", + "\n", + "import dbm\n", + "import dbm.ndbm\n", + "import dbm.dumb\n", + "import dbm.gnu\n", + "\n", + "# Python 2 and 3: alternative 2\n", + "from future.moves import dbm\n", + "from future.moves.dbm import dumb\n", + "from future.moves.dbm import ndbm\n", + "from future.moves.dbm import gnu\n", + "\n", + "# Python 2 and 3: alternative 3\n", + "from six.moves import dbm_gnu\n", + "# (others not supported)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### commands / subprocess modules" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "from commands import getoutput, getstatusoutput\n", + "\n", + "# Python 2 and 3\n", + "from future import standard_library\n", + "standard_library.install_aliases()\n", + "\n", + "from subprocess import getoutput, getstatusoutput" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### subprocess.check_output()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2.7 and above\n", + "from subprocess import check_output\n", + "\n", + "# Python 2.6 and above: alternative 1\n", + "from future.moves.subprocess import check_output\n", + "\n", + "# Python 2.6 and above: alternative 2\n", + "from future import standard_library\n", + "standard_library.install_aliases()\n", + "\n", + "from subprocess import check_output" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### collections: Counter, OrderedDict, ChainMap" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2.7 and above\n", + "from collections import Counter, OrderedDict, ChainMap\n", + "\n", + "# Python 2.6 and above: alternative 1\n", + "from future.backports import Counter, OrderedDict, ChainMap\n", + "\n", + "# Python 2.6 and above: alternative 2\n", + "from future import standard_library\n", + "standard_library.install_aliases()\n", + "\n", + "from collections import Counter, OrderedDict, ChainMap" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### StringIO module" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only\n", + "from StringIO import StringIO\n", + "from cStringIO import StringIO" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3\n", + "from io import BytesIO\n", + "# and refactor StringIO() calls to BytesIO() if passing byte-strings" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### http module" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "import httplib\n", + "import Cookie\n", + "import cookielib\n", + "import BaseHTTPServer\n", + "import SimpleHTTPServer\n", + "import CGIHttpServer\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "import http.client\n", + "import http.cookies\n", + "import http.cookiejar\n", + "import http.server" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### xmlrpc module" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "import DocXMLRPCServer\n", + "import SimpleXMLRPCServer\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "import xmlrpc.server" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "import xmlrpclib\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "import xmlrpc.client" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### html escaping and entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3:\n", + "from cgi import escape\n", + "\n", + "# Safer (Python 2 and 3, after ``pip install future``):\n", + "from html import escape\n", + "\n", + "# Python 2 only:\n", + "from htmlentitydefs import codepoint2name, entitydefs, name2codepoint\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "from html.entities import codepoint2name, entitydefs, name2codepoint" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### html parsing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "from HTMLParser import HTMLParser\n", + "\n", + "# Python 2 and 3 (after ``pip install future``)\n", + "from html.parser import HTMLParser\n", + "\n", + "# Python 2 and 3 (alternative 2):\n", + "from future.moves.html.parser import HTMLParser" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### urllib module" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``urllib`` is the hardest module to use from Python 2/3 compatible code. You may like to use Requests (http://python-requests.org) instead." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "from urlparse import urlparse\n", + "from urllib import urlencode\n", + "from urllib2 import urlopen, Request, HTTPError" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 3 only:\n", + "from urllib.parse import urlparse, urlencode\n", + "from urllib.request import urlopen, Request\n", + "from urllib.error import HTTPError" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: easiest option\n", + "from future.standard_library import install_aliases\n", + "install_aliases()\n", + "\n", + "from urllib.parse import urlparse, urlencode\n", + "from urllib.request import urlopen, Request\n", + "from urllib.error import HTTPError" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 2\n", + "from future.standard_library import hooks\n", + "\n", + "with hooks():\n", + " from urllib.parse import urlparse, urlencode\n", + " from urllib.request import urlopen, Request\n", + " from urllib.error import HTTPError" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 3\n", + "from future.moves.urllib.parse import urlparse, urlencode\n", + "from future.moves.urllib.request import urlopen, Request\n", + "from future.moves.urllib.error import HTTPError\n", + "# or\n", + "from six.moves.urllib.parse import urlparse, urlencode\n", + "from six.moves.urllib.request import urlopen\n", + "from six.moves.urllib.error import HTTPError" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 and 3: alternative 4\n", + "try:\n", + " from urllib.parse import urlparse, urlencode\n", + " from urllib.request import urlopen, Request\n", + " from urllib.error import HTTPError\n", + "except ImportError:\n", + " from urlparse import urlparse\n", + " from urllib import urlencode\n", + " from urllib2 import urlopen, Request, HTTPError" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tkinter" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "import Tkinter\n", + "import Dialog\n", + "import FileDialog\n", + "import ScrolledText\n", + "import SimpleDialog\n", + "import Tix \n", + "import Tkconstants\n", + "import Tkdnd \n", + "import tkColorChooser\n", + "import tkCommonDialog\n", + "import tkFileDialog\n", + "import tkFont\n", + "import tkMessageBox\n", + "import tkSimpleDialog\n", + "import ttk\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "import tkinter\n", + "import tkinter.dialog\n", + "import tkinter.filedialog\n", + "import tkinter.scrolledtext\n", + "import tkinter.simpledialog\n", + "import tkinter.tix\n", + "import tkinter.constants\n", + "import tkinter.dnd\n", + "import tkinter.colorchooser\n", + "import tkinter.commondialog\n", + "import tkinter.filedialog\n", + "import tkinter.font\n", + "import tkinter.messagebox\n", + "import tkinter.simpledialog\n", + "import tkinter.ttk" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### socketserver" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "import SocketServer\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "import socketserver" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### copy_reg, copyreg" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "import copy_reg\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "import copyreg" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### configparser" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "from ConfigParser import ConfigParser\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "from configparser import ConfigParser" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### queue" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "from Queue import Queue, heapq, deque\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "from queue import Queue, heapq, deque" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### repr, reprlib" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "from repr import aRepr, repr\n", + "\n", + "# Python 2 and 3 (after ``pip install future``):\n", + "from reprlib import aRepr, repr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### UserDict, UserList, UserString" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "from UserDict import UserDict\n", + "from UserList import UserList\n", + "from UserString import UserString\n", + "\n", + "# Python 3 only:\n", + "from collections import UserDict, UserList, UserString\n", + "\n", + "# Python 2 and 3: alternative 1\n", + "from future.moves.collections import UserDict, UserList, UserString\n", + "\n", + "# Python 2 and 3: alternative 2\n", + "from six.moves import UserDict, UserList, UserString\n", + "\n", + "# Python 2 and 3: alternative 3\n", + "from future.standard_library import install_aliases\n", + "install_aliases()\n", + "from collections import UserDict, UserList, UserString" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### itertools: filterfalse, zip_longest" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# Python 2 only:\n", + "from itertools import ifilterfalse, izip_longest\n", + "\n", + "# Python 3 only:\n", + "from itertools import filterfalse, zip_longest\n", + "\n", + "# Python 2 and 3: alternative 1\n", + "from future.moves.itertools import filterfalse, zip_longest\n", + "\n", + "# Python 2 and 3: alternative 2\n", + "from six.moves import filterfalse, zip_longest\n", + "\n", + "# Python 2 and 3: alternative 3\n", + "from future.standard_library import install_aliases\n", + "install_aliases()\n", + "from itertools import filterfalse, zip_longest" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.4.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} |
