{
 "metadata": {
  "name": "",
  "signature": "sha256:eaa779f53a8d92661faf4a195319512f3591fefdda4f03323cdfe77daedec480"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "What's new in Python 3.4"
     ]
    },
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "[PEP 443](https://www.python.org/dev/peps/pep-0443/):\n",
      "[Single-Dispatch Generic Functions](https://docs.python.org/3/library/functools.html#functools.singledispatch)"
     ]
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "How to dispatch on type - Ye olde way"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "len(\"asdf\")"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 1,
       "text": [
        "4"
       ]
      }
     ],
     "prompt_number": 1
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "len([1, 2, 3, 4, 5])"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 2,
       "text": [
        "5"
       ]
      }
     ],
     "prompt_number": 2
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The above works because `len()` actually calls the `__len__` special method on its argument.\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "[1, 2, 3, 4, 5].__len__()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 3,
       "text": [
        "5"
       ]
      }
     ],
     "prompt_number": 3
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Alternatively, you can do it by hand."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def p(arg):\n",
      "    if isinstance(arg, list):\n",
      "        print(\"a list:\")\n",
      "        for e in enumerate(arg):\n",
      "            print(\"{}: {}\".format(*e))\n",
      "    elif isinstance(arg, str):\n",
      "        print(\"a string:\", arg)\n",
      "        \n",
      "    else:\n",
      "        print(\"an unknown object:\", repr(arg))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 4
    },
    {
     "cell_type": "code",
     "collapsed": true,
     "input": [
      "p([1, 2, 3, 4, 5]), p({})"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "a list:\n",
        "0: 1\n",
        "1: 2\n",
        "2: 3\n",
        "3: 4\n",
        "4: 5\n",
        "an unknown object: {}\n"
       ]
      },
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 5,
       "text": [
        "(None, None)"
       ]
      }
     ],
     "prompt_number": 5
    },
    {
     "cell_type": "heading",
     "level": 3,
     "metadata": {},
     "source": [
      "The \"uniform API to address dynamic overloading using decorators\" way"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from functools import singledispatch\n",
      "\n",
      "@singledispatch\n",
      "def pp(arg, verbose=False):\n",
      "    print(\"an object:\", repr(arg))\n",
      "    "
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 6
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp(\"asdf\"), pp(123), pp([])"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "an object: 'asdf'\n",
        "an object: 123\n",
        "an object: []\n"
       ]
      },
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 7,
       "text": [
        "(None, None, None)"
       ]
      }
     ],
     "prompt_number": 7
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "@pp.register(list)\n",
      "def pp_list(arg):\n",
      "    print(\"a list:\")\n",
      "    for e in enumerate(arg):\n",
      "        print(\"{}: {}\".format(*e))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 8
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp(\"asfd\")"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "an object: 'asfd'\n"
       ]
      }
     ],
     "prompt_number": 9
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp([1, 2, 3, 4, 5])"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "a list:\n",
        "0: 1\n",
        "1: 2\n",
        "2: 3\n",
        "3: 4\n",
        "4: 5\n"
       ]
      }
     ],
     "prompt_number": 10
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The `register` decorator returns the undecorated function, so types can be stacked:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "@pp.register(int)\n",
      "@pp.register(float)\n",
      "def pp_number(obj):\n",
      "    print(\"a number:\", obj)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 11
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp(1)\n"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "a number: 1\n"
       ]
      }
     ],
     "prompt_number": 12
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp(1.0)\n"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "a number: 1.0\n"
       ]
      }
     ],
     "prompt_number": 13
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Call `register` on existing or anonymous functions:"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp.register(type(None), lambda _: print(\"nothing\"))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 14,
       "text": [
        "<function __main__.<lambda>>"
       ]
      }
     ],
     "prompt_number": 14
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp(None)\n"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "nothing\n"
       ]
      }
     ],
     "prompt_number": 15
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Which specific function would be called?"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp.dispatch(list)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 16,
       "text": [
        "<function __main__.pp_list>"
       ]
      }
     ],
     "prompt_number": 16
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp.dispatch(int)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 17,
       "text": [
        "<function __main__.pp_number>"
       ]
      }
     ],
     "prompt_number": 17
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "The MRO is used to handle unknown types. The function decorated with `singledispatch` is used for `object`."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp.dispatch(dict)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 18,
       "text": [
        "<function __main__.pp>"
       ]
      }
     ],
     "prompt_number": 18
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "pp.registry.keys()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 19,
       "text": [
        "dict_keys([<class 'list'>, <class 'NoneType'>, <class 'object'>, <class 'float'>, <class 'int'>])"
       ]
      }
     ],
     "prompt_number": 19
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "There is a [backport on pypi](https://pypi.python.org/pypi/singledispatch) and an older implementation in the pkgutil module in Python 2 (not exportet via `__all__`):"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from pkgutil import simplegeneric"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 20
    }
   ],
   "metadata": {}
  }
 ]
}