Skip to content

Instantly share code, notes, and snippets.

@brydavis
Created August 27, 2019 17:53
Show Gist options
  • Save brydavis/0b8d4ed47d75fcf26617c1a5c91443aa to your computer and use it in GitHub Desktop.
Save brydavis/0b8d4ed47d75fcf26617c1a5c91443aa to your computer and use it in GitHub Desktop.
Examples of creating and using decorators in Python
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Decorator Examples"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"('HELLO', 'UPPER', 'WORLD')\n"
]
}
],
"source": [
"def upper(fn):\n",
" def wrapper(*args):\n",
" args = [str(a).upper() for a in args]\n",
" return fn(*args)\n",
" return wrapper\n",
" \n",
"@upper\n",
"def just_print(*strings):\n",
" print(strings)\n",
" \n",
"just_print(\"hello\", \"upper\", \"world\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1035.0\n",
"5175.0\n",
"0\n"
]
}
],
"source": [
"def apply_interest_rate(rate):\n",
" def decorator(fn):\n",
" def wrapper(*args):\n",
" args = [\n",
" a * (1+rate) \n",
" if a <= 10000 else 0\n",
" for a in args\n",
" ]\n",
" return fn(*args)\n",
" return wrapper\n",
" return decorator\n",
" \n",
"@apply_interest_rate(0.035)\n",
"def create_loans(*amounts):\n",
" for amount in amounts:\n",
" print(amount)\n",
"\n",
"create_loans(1000, 5000, 20000)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"some\n",
"very\n",
"very\n",
"special\n",
"logging\n",
"do_work\n",
"doing some more work\n"
]
}
],
"source": [
"def special_logger(fn):\n",
" # anything done here will happen \n",
" # when decorator is set, not called\n",
" def w():\n",
" print(\"some\")\n",
" print(\"very\")\n",
" print(\"very\")\n",
" print(\"special\")\n",
" print(\"logging\")\n",
" print(fn.__name__)\n",
" return fn()\n",
" return w\n",
"\n",
"@special_logger\n",
"def do_work():\n",
" print(\"doing some more work\")\n",
" \n",
"do_work() "
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"adding some awesome while...\n",
"doing some stuff\n",
"---------\n",
"no more boring, just awesomeness!\n",
"---------\n",
"Hello Ruby\n",
"---------\n"
]
}
],
"source": [
"import time\n",
"\n",
"class awesome:\n",
" def add(fn):\n",
" def wrap():\n",
" print(\"adding some awesome while...\")\n",
" return fn()\n",
" return wrap\n",
" \n",
" def swap(fn):\n",
" def replacement():\n",
" print(\"no more boring, just awesomeness!\")\n",
" return replacement\n",
" \n",
" def pause(seconds):\n",
" def decor(fn):\n",
" def wrap(name):\n",
" time.sleep(seconds)\n",
" return fn(name)\n",
" return wrap\n",
" return decor\n",
" \n",
"\n",
"\n",
"@awesome.add\n",
"def some_stuff():\n",
" print(\"doing some stuff\")\n",
"\n",
"@awesome.swap\n",
"def boring():\n",
" print(\"so boring\")\n",
" \n",
"@awesome.pause(5)\n",
"def hello(name):\n",
" print(f\"Hello {name}\")\n",
" \n",
"some_stuff()\n",
"print(\"---------\")\n",
"boring()\n",
"print(\"---------\")\n",
"hello(\"Ruby\")\n",
"print(\"---------\")"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Execution time: 5.000079154968262\n"
]
}
],
"source": [
"from time import time, sleep\n",
"\n",
"def timely(fn):\n",
" def wrapper(*args, **kwargs):\n",
" start = time()\n",
" result = fn(*args, **kwargs)\n",
" end = time()\n",
" print(\"Execution time: {}\".format(end - start))\n",
" return result\n",
" return wrapper\n",
"\n",
"@timely\n",
"def sleepy():\n",
" # function will take\n",
" # at least 5 seconds\n",
" sleep(5)\n",
" \n",
"sleepy()"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Whee!\n",
"Whee!\n",
"---------\n",
"Hello Jody\n",
"Hello Jody\n",
"Hello Jody\n",
"Hello Jody\n",
"Hello Jody\n"
]
}
],
"source": [
"def repeat(fn=None, times=2):\n",
" def decorator(func):\n",
" def wrapper(*args, **kwargs):\n",
" for _ in range(times):\n",
" value = func(*args, **kwargs)\n",
" return value\n",
" return wrapper\n",
"\n",
" if fn is None:\n",
" return decorator\n",
" else:\n",
" return decorator(fn)\n",
" \n",
"@repeat\n",
"def say_whee():\n",
" print(\"Whee!\")\n",
"\n",
"@repeat(times=5)\n",
"def howdy(name):\n",
" print(f\"Hello {name}\")\n",
" \n",
"\n",
"say_whee() \n",
"print(\"---------\")\n",
"howdy(\"Jody\")"
]
},
{
"cell_type": "code",
"execution_count": 69,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<div>HELLO-UPPER-WORLD</div>\n"
]
}
],
"source": [
"# HTML Wrapper with Decorators\n",
"\n",
"def bookend(tag):\n",
" left = f\"<{tag}>\"\n",
" right = f\"</{tag}>\"\n",
" def decor_bookend(fn):\n",
" def wrapper(string):\n",
" return fn(left + string + right)\n",
" return wrapper\n",
" return decor_bookend\n",
" \n",
"\n",
"def hyphens(fn):\n",
" def wrapper(*args):\n",
" return fn(\"-\".join([str(a) for a in args]))\n",
" return wrapper\n",
" \n",
"\n",
"def upper(fn):\n",
" def wrapper(*args):\n",
" args = [str(a).upper() for a in args]\n",
" return fn(*args)\n",
" return wrapper\n",
"\n",
"@upper\n",
"@hyphens\n",
"@bookend(\"div\")\n",
"def just_print(*strings):\n",
" print(*strings)\n",
" \n",
"just_print(\"hello\", \"upper\", \"world\")"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'<div>HELLO-UPPER-WORLD</div>'"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# HTML Wrapper without Decorators\n",
" \n",
"def bookend_not_decorator(tag):\n",
" left = f\"<{tag}>\"\n",
" right = f\"</{tag}>\"\n",
" def tagged(string):\n",
" return left + string + right\n",
" return tagged\n",
"\n",
"def hyphens(*args):\n",
" return \"-\".join([str(a) for a in args])\n",
" \n",
"\n",
"def upper(*args):\n",
" return [str(a).upper() for a in args]\n",
"\n",
"\n",
"# bookend(\"div\")(print)(\n",
"# hyphens(\n",
"# *upper(\"hello\", \"upper\", \"world\")\n",
"# )\n",
"# )\n",
"\n",
"bookend_not_decorator(\"div\")(\n",
" hyphens(\n",
" *upper(\"hello\", \"upper\", \"world\")\n",
" )\n",
")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.7.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
@brydavis
Copy link
Author

brydavis commented Aug 27, 2019

Notice that in the last example, we are NOT using decorators and yet achieve the same result.

In fact, we are using a couple of simple functions and a closure.

Like many features in Python, decorators may not always provide the simplest (or even Pythonic) way to write code.

Use wisely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment