Skip to content

Instantly share code, notes, and snippets.

@manuelinfosec
Created September 6, 2022 03:02
Show Gist options
  • Save manuelinfosec/5ac21010241545d4aca77d6dc70e3368 to your computer and use it in GitHub Desktop.
Save manuelinfosec/5ac21010241545d4aca77d6dc70e3368 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Python Decorators For Dummies\n",
"> The Best Explanation You Can Ever Find"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import discord\n",
"client = discord.Client(intents=intents)\n",
"\n",
"@client.event # take note of this line\n",
"async def on_ready():\n",
" print(f\"Logged in as {client.user}\")\n",
"\n",
"@client.event # take note of this line\n",
"async def on_message(msg):\n",
" if msg.content == \"\":\n",
" pass\n",
"# ... SOME MORE CODE ..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### A simple Python function"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Yes!\n"
]
}
],
"source": [
"def shout(word='yes'):\n",
" return word.capitalize() + '!'\n",
"\n",
"print(shout())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Python function assigned to a variable"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"scream = shout"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Calling the function from a variable"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Yes!\n"
]
}
],
"source": [
"print(scream())"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"name 'shout' is not defined\n",
"Yes!\n"
]
}
],
"source": [
"# deleting the shout() object\n",
"del shout\n",
"\n",
"try:\n",
"\t# trying to access the deleted shout() object\n",
" print(shout())\n",
"except NameError as e:\n",
" print(e)\n",
"\n",
"print(scream())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Defining functions within functions"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"yes...\n"
]
}
],
"source": [
"def talk():\n",
" # Defining a function on the fly in `talk` ...\n",
" def whisper(word='yes'):\n",
" return word.lower() + '...'\n",
" # ... and using it right away!\n",
" print(whisper())\n",
"\n",
"talk()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Internal functions don't exist beyond their scope"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"name 'whisper' is not defined\n"
]
}
],
"source": [
"try:\n",
" print(whisper())\n",
"except NameError as e:\n",
" print(e)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Function returning function"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"def getTalk(kind='shout'):\n",
" # We define functions on the fly\n",
" def shout(word='yes'):\n",
" return word.capitalize() + '!'\n",
"\n",
" def whisper(word='yes'):\n",
" return word.lower() + '...'\n",
"\n",
" # Then we return one of them\n",
" if kind == 'shout':\n",
"\t # What happened here?\n",
" return shout \n",
" else:\n",
" return whisper"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Driver code for the previous cell"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<function getTalk.<locals>.shout at 0x000001C34384AA60>\n",
"Yes!\n",
"yes...\n"
]
}
],
"source": [
"# Get the function and assign it to a variable\n",
"talk = getTalk() \n",
"\n",
"# You can see that `talk` is here a function object:\n",
"print(talk)\n",
"\n",
"# The object is the one returned by the function:\n",
"print(talk())\n",
"\n",
"# And you can even use it directly if you feel wild:\n",
"print(getTalk('whisper')())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Passing a function as parameter"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"I do something before then I call the function you gave me\n",
"Yes!\n"
]
}
],
"source": [
"def doSomethingBefore(func): \n",
" print(\"I do something before then I call the function you gave me\")\n",
" print(func())\n",
"\n",
"doSomethingBefore(scream)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Python Decorators The Hard Way"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"def my_shiny_new_decorator(a_function_to_decorate):\n",
" # Inside, the decorator defines a function on the fly: the wrapper.\n",
" # This function is going to be wrapped around the original function\n",
" # so it can execute code before and after it.\n",
" def the_wrapper_around_the_original_function():\n",
" \n",
" # Put here the code you want to be executed BEFORE the original \n",
" # function is called\n",
" print(\"Before the function runs\")\n",
"\n",
" # Call the function from the parameter here (using parentheses)\n",
" a_function_to_decorate()\n",
"\n",
" # Put here the code you want to be executed AFTER the original \n",
" # function is called\n",
" print(\"After the function runs\")\n",
"\n",
" # At this point, `a_function_to_decorate` HAS NEVER BEEN EXECUTED.\n",
" # We return the wrapper function we have just created.\n",
" # The wrapper contains the function and the code to execute before\n",
" # ...and after. It’s ready to use!\n",
" return the_wrapper_around_the_original_function"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Creating a standalone function"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"I am a stand alone function, don’t you dare modify me\n"
]
}
],
"source": [
"def a_stand_alone_function():\n",
" print(\"I am a stand alone function, don’t you dare modify me\")\n",
"\n",
"a_stand_alone_function() "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Wrapping the standalone function around a decorator"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Before the function runs\n",
"I am a stand alone function, don’t you dare modify me\n",
"After the function runs\n"
]
}
],
"source": [
"a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)\n",
"a_stand_alone_function_decorated()"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Before the function runs\n",
"I am a stand alone function, don’t you dare modify me\n",
"After the function runs\n"
]
}
],
"source": [
"a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)\n",
"a_stand_alone_function()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Python decorators the Pythonic way"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Before the function runs\n",
"Leave me alone\n",
"After the function runs\n"
]
}
],
"source": [
"@my_shiny_new_decorator\n",
"def another_stand_alone_function():\n",
" print(\"Leave me alone\")\n",
"\n",
"another_stand_alone_function()"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### A better example of Python decorators the naive way"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--ham--\n",
"</''''''\\>\n",
"#tomatoes#\n",
"--ham--\n",
"~salad~\n",
"<\\______/>\n"
]
}
],
"source": [
"def bread(func):\n",
" def wrapper():\n",
" print(\"</''''''\\>\")\n",
" func()\n",
" print(\"<\\______/>\")\n",
" return wrapper\n",
"\n",
"def ingredients(func):\n",
" def wrapper():\n",
" print(\"#tomatoes#\")\n",
" func()\n",
" print(\"~salad~\")\n",
" return wrapper\n",
"\n",
"def sandwich(food='--ham--'):\n",
" print(food)\n",
"\n",
"sandwich()\n",
"print()\n",
"# Outputs: --ham--\n",
"\n",
"sandwich = bread(ingredients(sandwich))\n",
"# sandwich is now reference to the decorator\n",
"# instead of the `--ham` string.\n",
"sandwich()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Python decorators the Pythonic way"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"</''''''\\>\n",
"#tomatoes#\n",
"--ham--\n",
"~salad~\n",
"<\\______/>\n"
]
}
],
"source": [
"@bread\n",
"@ingredients\n",
"def sandwich(food=\"--ham--\"):\n",
"\tprint(food)\n",
"\n",
"sandwich()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Unordered decorators"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"#tomatoes#\n",
"</''''''\\>\n",
"--ham--\n",
"<\\______/>\n",
"~salad~\n"
]
}
],
"source": [
"@ingredients\n",
"@bread\n",
"def strange_sandwich(food='--ham--'):\n",
" print(food)\n",
"\n",
"strange_sandwich()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.9.4 64-bit",
"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.9.4"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "82ed002fa2d4956f5c6aec99bcefe0f73a9f79882f3c9e2319b14958a5896ac5"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment