Last active
April 19, 2025 19:17
-
-
Save xarical/32673b18c98517bc08130ffdf8a1dc37 to your computer and use it in GitHub Desktop.
Explaining function decorators in Python - https://xarical.medium.com/what-are-function-decorators-in-python-1fab987e3f68
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "nbformat": 4, | |
| "nbformat_minor": 0, | |
| "metadata": { | |
| "colab": { | |
| "provenance": [], | |
| "authorship_tag": "ABX9TyOOEXPtm9JONiG5qS1O6+9g", | |
| "include_colab_link": true | |
| }, | |
| "kernelspec": { | |
| "name": "python3", | |
| "display_name": "Python 3" | |
| }, | |
| "language_info": { | |
| "name": "python" | |
| } | |
| }, | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { "id": "view-in-github", "colab_type": "text" }, | |
| "source": [ | |
| "<a href=\"https://colab.research.google.com/gist/xarical/32673b18c98517bc08130ffdf8a1dc37/function_decorators.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "source": [ | |
| "# <u> Function decorators </u>\n", | |
| "Function decorators allow us to modify the behavior of a function without modifying the function itself." | |
| ], | |
| "metadata": { | |
| "id": "Al1bkKS-nA0g" | |
| } | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "source": [ | |
| "\n", | |
| "\n", | |
| "---\n", | |
| "\n" | |
| ], | |
| "metadata": { | |
| "id": "_vUpxLtiomMT" | |
| } | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "source": [ | |
| "This is how you use a decorator:" | |
| ], | |
| "metadata": { | |
| "id": "WYHK0xoygSe2" | |
| } | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "def decorator(func):\n", | |
| " \"\"\"\n", | |
| " Prints \"before\" before running func(), \"after\" after running func(),\n", | |
| " and then returns the return from func() using any *args and **kwargs\n", | |
| " passed in.\n", | |
| "\n", | |
| " It works by returning a new_func() function that wraps the original\n", | |
| " function (which is passed in as the parameter \"func\")\n", | |
| " \"\"\"\n", | |
| "\n", | |
| " def new_func(*args, **kwargs):\n", | |
| " print(\"before\")\n", | |
| " result = func(*args, **kwargs)\n", | |
| " print(\"after\")\n", | |
| " return result\n", | |
| "\n", | |
| " return new_func\n", | |
| "\n", | |
| "def calculate_sum(a, b):\n", | |
| " \"\"\"\n", | |
| " This is the original function. It prints \"inside\" and then returns the\n", | |
| " sum of the parameters.\n", | |
| " \"\"\"\n", | |
| "\n", | |
| " print(\"inside\")\n", | |
| " return a + b\n", | |
| "\n", | |
| "# Assigning calculate_sum to the function returned by decorator(calculate_sum)\n", | |
| "# It works, but there's a better way to do this...\n", | |
| "calculate_sum = decorator(calculate_sum)\n", | |
| "\n", | |
| "# Calling the new calculate_sum\n", | |
| "print(\"sum =\", calculate_sum(1, 1))" | |
| ], | |
| "metadata": { | |
| "colab": { | |
| "base_uri": "https://localhost:8080/" | |
| }, | |
| "outputId": "a46ee312-4005-4bf1-fbae-e1691c75e790", | |
| "id": "NARpX33WnA0h" | |
| }, | |
| "execution_count": null, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "before\n", | |
| "inside\n", | |
| "after\n", | |
| "sum = 2\n" | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "source": [ | |
| "It works, but there's a better way to do this. You can instead use decorator syntax." | |
| ], | |
| "metadata": { | |
| "id": "cn_ELY2fhOAN" | |
| } | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "def decorator(func):\n", | |
| " \"\"\"\n", | |
| " This is the same decorator function from earlier. Nothing has changed\n", | |
| " \"\"\"\n", | |
| "\n", | |
| " def new_func(*args, **kwargs):\n", | |
| " print(\"before\")\n", | |
| " result = func(*args, **kwargs)\n", | |
| " print(\"after\")\n", | |
| " return result\n", | |
| "\n", | |
| " return new_func\n", | |
| "\n", | |
| "@decorator\n", | |
| "def calculate_sum(a, b):\n", | |
| " \"\"\"\n", | |
| " This is the same original function from earlier, BUT using decorator\n", | |
| " syntax (the @decorator on top)\n", | |
| " \"\"\"\n", | |
| "\n", | |
| " print(\"inside\")\n", | |
| " return a + b\n", | |
| "\n", | |
| "print(\"sum =\", calculate_sum(1, 1))" | |
| ], | |
| "metadata": { | |
| "colab": { | |
| "base_uri": "https://localhost:8080/" | |
| }, | |
| "outputId": "4e945f6a-54a3-4791-fb7f-f25376331290", | |
| "id": "qB5D0PzSnA0i" | |
| }, | |
| "execution_count": null, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "before\n", | |
| "inside\n", | |
| "after\n", | |
| "sum = 2\n" | |
| ] | |
| } | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "source": [ | |
| "The output is the same, but instead of `calculate_sum = decorator(calculate_sum)` after the original function, you write `@decorator` on top of it. It looks nicer and is more organized." | |
| ], | |
| "metadata": { | |
| "id": "o3C4ODeFhRrx" | |
| } | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "source": [ | |
| "\n", | |
| "\n", | |
| "---\n", | |
| "\n" | |
| ], | |
| "metadata": { | |
| "id": "eCy0mZ_Moi8z" | |
| } | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "source": [ | |
| "Example: A decorator that makes the *args passed to the function lowercase\n" | |
| ], | |
| "metadata": { | |
| "id": "-w2go3_BnA0j" | |
| } | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "def lowercase_user_input(func):\n", | |
| " \"\"\"\n", | |
| " This function prints the result of func() if the *args was all lowercase.\n", | |
| "\n", | |
| " It works the same as the decorator() function from earlier; it returns a\n", | |
| " lowercase_func() function that wraps the original function (which, like earlier,\n", | |
| " is passed in as the parameter \"func\")\n", | |
| " \"\"\"\n", | |
| "\n", | |
| " def lowercase_func(*args):\n", | |
| " lowercase_args = [arg.lower() for arg in args]\n", | |
| " result = func(*lowercase_args)\n", | |
| " return result\n", | |
| "\n", | |
| " return lowercase_func\n", | |
| "\n", | |
| "# Now we can make many functions, and easily have them convert any arguments into\n", | |
| "# lowercase just by adding @lowercase_user_input at the top.\n", | |
| "@lowercase_user_input\n", | |
| "def handle_user_input(input):\n", | |
| " \"\"\"\n", | |
| " This function returns True if the input is y, and False if it is n.\n", | |
| " \"\"\"\n", | |
| "\n", | |
| " if input == \"y\":\n", | |
| " return True\n", | |
| " elif input == \"n\":\n", | |
| " return False\n", | |
| " else:\n", | |
| " return \"Invalid input\"\n", | |
| "\n", | |
| "# more functions using @lowercase_user_input here...\n", | |
| "\n", | |
| "user_input = input(\"Enter y or n (not case sensitive): \")\n", | |
| "print(\"User input is y:\", handle_user_input(user_input))" | |
| ], | |
| "metadata": { | |
| "colab": { | |
| "base_uri": "https://localhost:8080/" | |
| }, | |
| "outputId": "9118f5a2-4698-46f6-c514-8154fafabfa2", | |
| "id": "E_Ebgx98nA0j" | |
| }, | |
| "execution_count": null, | |
| "outputs": [ | |
| { | |
| "output_type": "stream", | |
| "name": "stdout", | |
| "text": [ | |
| "Enter y or n (not case sensitive): Y\n", | |
| "User input is y: True\n" | |
| ] | |
| } | |
| ] | |
| } | |
| ] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment