{ "metadata": { "name": "", "signature": "sha256:43419e591b7a38d47f99119988b3544b9f9665624cb43c30656c49d53794bb0f" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Decorators in Python\n", "> Shrayas (@shrayasr)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#Recap on Functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Functions can be defined inside functions" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def say_something(thought):\n", " \n", " def _thought_makes_sense(thought):\n", " return True\n", " \n", " if _thought_makes_sense(thought):\n", " return thought\n", " \n", "print say_something(\"That person stinks!\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "That person stinks!\n" ] } ], "prompt_number": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Functions are Lexically scoped" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def say_something(thought):\n", " \n", " def _thought_makes_sense():\n", " print \"HMMM \\\"\"+thought+\"\\\"... I Wonder...\"\n", " return True\n", " \n", " if _thought_makes_sense():\n", " return thought\n", " \n", "print say_something(\"That person stinks!\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "HMMM \"That person stinks!\"... I Wonder...\n", "That person stinks!\n" ] } ], "prompt_number": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Functions can be passed as arguments to other Functions" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def say_something(thought, tone=None):\n", " return tone(thought)\n", "\n", "def yell(thought):\n", " return thought.upper()\n", "\n", "def whisper(thought):\n", " return \"Shhh... \" + thought.lower()\n", "\n", "print say_something(\"where are you babu?\", tone=yell)\n", "print say_something(\"Lets go get an ice cream!\", tone=whisper)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "WHERE ARE YOU BABU?\n", "Shhh... lets go get an ice cream!\n" ] } ], "prompt_number": 28 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. Functions can be returned from functions" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def mood_maker(mood):\n", " \n", " def happy(thought):\n", " return \"^_^ \" + thought + \" ^_^\"\n", " \n", " def sad(thought):\n", " return thought + \" ... :'( sniff\"\n", " \n", " moods = {\n", " \"HAPPY\": happy,\n", " \"SAD\": sad\n", " }\n", " \n", " return moods[mood.upper()]\n", "\n", "say_happily = mood_maker(\"happy\")\n", "print say_happily(\"Hello!\")\n", "\n", "say_sadly = mood_maker(\"sad\")\n", "print say_sadly(\"I lost my favourite pen!\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "^_^ Hello! ^_^\n", "I lost my favourite pen! ... :'( sniff\n" ] } ], "prompt_number": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#Back to business" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lets add some masala to a function!" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def masala_adder(func):\n", " \n", " def masalad_function():\n", " return \"^#!^^@) [\" + func() + \"] !@&$**^&$\"\n", " \n", " return masalad_function\n", "\n", "def say_hi():\n", " return \"Hii\"\n", " \n", "print say_hi()\n", "masala_say_hi = masala_adder(say_hi)\n", "print masala_say_hi()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Hii\n", "^#!^^@) [Hii] !@&$**^&$\n" ] } ], "prompt_number": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Masala, Decorators style!" ] }, { "cell_type": "code", "collapsed": false, "input": [ "@masala_adder\n", "def say_hello():\n", " return \"Hello\"\n", "\n", "say_hello()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 31, "text": [ "'^#!^^@) [Hello] !@&$**^&$'" ] } ], "prompt_number": 31 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Wait, what?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "say_hello = masala_adder(say_hello)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 32 }, { "cell_type": "markdown", "metadata": {}, "source": [ ">Decorators are just syntactic sugar on a function that takes a function and returns a replacement function\n", "\n", " A.K.A\n", "\n", "> Wrappers" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Define decorator here\n", "def decorator(func):\n", " \n", " def new_func():\n", " print \"before\"\n", " func()\n", " print \"after\"\n", " \n", " return new_func\n", "\n", "@decorator\n", "def say_hello():\n", " print \"Hello!\"\n", " \n", "say_hello()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "before\n", "Hello!\n", "after\n" ] } ], "prompt_number": 33 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lets make some owls!" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def ears(func): \n", " def ears_wrapper():\n", " owl_string = \" /\\\\_/\\\\\\n\"\n", " owl_string += func()\n", " return owl_string\n", " \n", " return ears_wrapper\n", "\n", "def eyes(func): \n", " def eyes_wrapper():\n", " owl_string = \" (O.O) \\n\"\n", " owl_string += func()\n", " return owl_string\n", " \n", " return eyes_wrapper\n", "\n", "def body(func): \n", " def body_wrapper():\n", " owl_string = \" (= =)\\n\"\n", " owl_string += func()\n", " return owl_string\n", " \n", " return body_wrapper\n", "\n", "def legs(func): \n", " def legs_wrapper():\n", " owl_string = \" ^^^\\n\"\n", " owl_string += func()\n", " return owl_string\n", " \n", " return legs_wrapper\n", "\n", "@ears\n", "@eyes\n", "@body\n", "@legs\n", "def owl():\n", " return \"hoot hoot\"\n", "\n", "print owl()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " /\\_/\\\n", " (O.O) \n", " (= =)\n", " ^^^\n", "hoot hoot\n" ] } ], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "owl = ears(eyes(body(legs(owl))))" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 35 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arguments to decorated functions" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def decorator(func):\n", " def new_func(arg1, arg2):\n", " print \"I R HAZ ARGZ! [%s, %s]\" % (arg1, arg2)\n", " return func(arg1, arg2)\n", " return new_func\n", "\n", "@decorator\n", "def sum_of_squares(num1, num2):\n", " print num1*num1 + num2*num2\n", " \n", "sum_of_squares(1,2)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "I R HAZ ARGZ! [1, 2]\n", "5\n" ] } ], "prompt_number": 36 }, { "cell_type": "code", "collapsed": false, "input": [ "def logger(func):\n", " def decorated_function(*args, **kwargs):\n", " print \"[INFO][Arguments]\", args, kwargs\n", " return func(*args, **kwargs)\n", " return decorated_function\n", "\n", "@logger\n", "def sum_of_squares(num1, num2):\n", " print num1*num1 + num2*num2\n", " \n", "@logger\n", "def csv_reader(file_path, record_delimiter=\",\", line_delimiter=\"\\n\"):\n", " print \"reading csv\"\n", " \n", "sum_of_squares(1,2)\n", "csv_reader(\"/etc/init.d\", record_delimiter=\";\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[INFO][Arguments] (1, 2) {}\n", "5\n", "[INFO][Arguments] ('/etc/init.d',) {'record_delimiter': ';'}\n", "reading csv\n" ] } ], "prompt_number": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise: Lets use decorators!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Let us write a small cache!" ] }, { "cell_type": "code", "collapsed": false, "input": [ "_cache = {}\n", "\n", "\"\"\"\n", "1_2 => 3\n", "\"\"\"\n", "\n", "def cache(func):\n", " \n", " def new_func(*args, **kwargs):\n", " \n", " key_str = \"\"\n", " for arg in args:\n", " key_str += str(arg) + \"_\"\n", " key_str = key_str[:-1]\n", " \n", " val = _cache.get(key_str)\n", " if not val:\n", " val = func(*args)\n", " _cache[key_str] = val\n", " return val\n", " \n", " return new_func" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 38 }, { "cell_type": "code", "collapsed": false, "input": [ "import time\n", "\n", "@cache\n", "def add_2_nos(a,b):\n", " time.sleep(2)\n", " return a+b" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 39 }, { "cell_type": "code", "collapsed": false, "input": [ "add_2_nos(1,2)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 40, "text": [ "3" ] } ], "prompt_number": 40 }, { "cell_type": "code", "collapsed": false, "input": [ "add_2_nos(1,2)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 41, "text": [ "3" ] } ], "prompt_number": 41 }, { "cell_type": "code", "collapsed": false, "input": [ "add_2_nos(10,20)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 42, "text": [ "30" ] } ], "prompt_number": 42 }, { "cell_type": "code", "collapsed": false, "input": [ "add_2_nos(10,20)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 43, "text": [ "30" ] } ], "prompt_number": 43 }, { "cell_type": "code", "collapsed": false, "input": [ "_cache" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 44, "text": [ "{'10_20': 30, '1_2': 3}" ] } ], "prompt_number": 44 }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Fin." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![boom](./blown.gif)" ] } ], "metadata": {} } ] }