{
 "metadata": {
  "name": "",
  "signature": "sha256:9cc2952acf30c46b9df46e340c85ba8e55d8ea0b4beb344d082f2db27e2a70ed"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "Decorators"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def foo():\n",
      "    return 123\n",
      "foo()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 8,
       "text": [
        "123"
       ]
      }
     ],
     "prompt_number": 8
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def double(func):\n",
      "    return lambda: func() * 2\n",
      "foo = double(foo) # redefine foo\n",
      "foo()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 9,
       "text": [
        "246"
       ]
      }
     ],
     "prompt_number": 9
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# decorators are just syntactic sugar for the above:\n",
      "@double\n",
      "def bar():\n",
      "    return \"asdf\"\n",
      "bar()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 10,
       "text": [
        "'asdfasdf'"
       ]
      }
     ],
     "prompt_number": 10
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "What happens when?"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def logit(func):\n",
      "    print('inside logit, before wrapper is defined')\n",
      "    def wrapper(a):\n",
      "        print('inside wrapper, before func is called')\n",
      "        result = func(a)\n",
      "        print ('after call to func, result =', result)\n",
      "        return result\n",
      "    print ('inside logit, after wrapper is defined')\n",
      "    return wrapper"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 11
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def square(x):\n",
      "    return x * x\n",
      "square(3)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 16,
       "text": [
        "9"
       ]
      }
     ],
     "prompt_number": 16
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "logged_square = logit(square)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "inside logit, before wrapper defined\n",
        "inside logit, after wrapper defined\n"
       ]
      }
     ],
     "prompt_number": 17
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "logged_square(4)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "inside wrapper, before\n",
        "after call to func, result = 16\n"
       ]
      },
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 18,
       "text": [
        "16"
       ]
      }
     ],
     "prompt_number": 18
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "logged_square() # here the error happens when calling `wrapper`"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "ename": "TypeError",
       "evalue": "wrapper() missing 1 required positional argument: 'a'",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[0;32m<ipython-input-19-76ac99888a96>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mlogged_square\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[0;31mTypeError\u001b[0m: wrapper() missing 1 required positional argument: 'a'"
       ]
      }
     ],
     "prompt_number": 19
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "square() # Note: here it's `square`"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "ename": "TypeError",
       "evalue": "square() missing 1 required positional argument: 'x'",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[0;32m<ipython-input-21-514c4eeba5e6>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0msquare\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Note: here it's `square`\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[0;31mTypeError\u001b[0m: square() missing 1 required positional argument: 'x'"
       ]
      }
     ],
     "prompt_number": 21
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Real world example (eg. for testing)"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "#@with_temporary_transaction\n",
      "#def foo(db):\n",
      "#    db.execute(\"...\")\n",
      "#foo()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 24
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "And something for URL routing in a web framework"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "globalregistry = {}\n",
      "\n",
      "def register(path):\n",
      "    print('start of register, path =', path)\n",
      "    def decorator(func):\n",
      "        print('start of decorator, func=', func)\n",
      "        globalregistry[path] = func\n",
      "        setattr(func, 'path', path)\n",
      "        print('end of decorator, returning', func)\n",
      "        return func\n",
      "    print('end of register, returning', decorator)\n",
      "    return decorator\n",
      "\n",
      "print('A')\n",
      "print('B')\n",
      "print(globalregistry)\n",
      "@register('/index.html')\n",
      "def webpage():\n",
      "    print('inside webpage')\n",
      "    return \"<blink>yeah</blink>\"\n",
      "web = register('/index.html')(webpage)\n",
      "print(globalregistry)\n",
      "print(webpage.path)\n",
      "print('C')\n",
      "print('calling webpage directly:', webpage())\n",
      "print('D')\n",
      "def get(path):\n",
      "    return globalregistry[path]()\n",
      "print('E')\n",
      "print('calling via get:', get(\"/index.html\"))\n",
      "print('F')"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "A\n",
        "B\n",
        "{}\n",
        "start of register, path = /index.html\n",
        "end of register, returning <function register.<locals>.decorator at 0x108d1c2f0>\n",
        "start of decorator, func= <function webpage at 0x108d1c268>\n",
        "end of decorator, returning <function webpage at 0x108d1c268>\n",
        "start of register, path = /index.html\n",
        "end of register, returning <function register.<locals>.decorator at 0x108d1cc80>\n",
        "start of decorator, func= <function webpage at 0x108d1c268>\n",
        "end of decorator, returning <function webpage at 0x108d1c268>\n",
        "{'/index.html': <function webpage at 0x108d1c268>}\n",
        "/index.html\n",
        "C\n",
        "inside webpage\n",
        "calling webpage directly: <blink>yeah</blink>\n",
        "D\n",
        "E\n",
        "inside webpage\n",
        "calling via get: <blink>yeah</blink>\n",
        "F\n"
       ]
      }
     ],
     "prompt_number": 25
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": []
    }
   ],
   "metadata": {}
  }
 ]
}