Python Decorator with sample

LORY
3 min readDec 27, 2020

--

Decorator is one of the powerful tool in meta programming . in python it is very simple to define and use a decorator

1. Function level decorator

Sample #1 function execution time

import time, random
def exe_time(func):
print('before declaration...')
def inner_func(*arg, **kwargs):
arg_str = ','.join(list(map(str,arg)))
print(f'===args: {arg_str}===')

print(f'==keywarded args ==')
for k,v in kwargs.items():
print(f'{k}:{v}')
start = time.time()
print('before executing...')
res = func(*arg, **kwargs)
end=time.time()
total = round(end-start,3)
print(f'after executing...total {total}')
return res
print('after declaration...')
return inner_func
@exe_time
def test(n,n2,p1='a',p2='b'):
res=0
for i in range(n):
wait = random.randint(0,2)*i
res+=wait
time.sleep(wait)
print(f'total wait :{round(res,2)} seconds')
return res

Sample #2 Create a simple memory cache

import functools
import math
def cache_res(func):
def inner(*arg, **kwarg):
key = arg+tuple(kwarg.items())
if key not in inner.cache:
inner.cache[key] = func(*arg, **kwarg)
return inner.cache[key]
inner.cache = {}
return inner
@cache_res
def test_compute(n):
res= math.sqrt(n)+ math.sin(n) * math.cos(n)
print(f'calculated result of :{n} -- {res}')
return res
"""
only calculated 2 times
"""
if __name__ == "__main__":
print(test_compute(10))
print(test_compute(10))
print(test_compute(5))
print(test_compute(5))
print(test_compute(5))

Class Level decorator

Sample#2 “template” id class field

import uuiddef add_id(cls):
init = cls.__init__
def my_init(self, *args, **kwargs):
self.id = uuid.uuid1()
init(self, *args, **kwargs)
cls.__init__ = my_init
return cls
@add_id
class person:
def __init__(self,name):
self.name=name
def __str__(self):
return f'{self.id},{self.name}'
def test_add_id():
p = person('jeo')
print(p)
if __name__ == "__main__":
test_add_id()

Sample#2 Call counter

import functoolsclass call_counter:
def __init__(self, f):
functools.update_wrapper(self, f)
self.func = f
self.num = 0
def __call__(self, *args, **kwargs):
self.num +=1
print(f'called {self.num} times')
return self.func(*args, **kwargs)
@call_counter
def test_call():
print("testing")
if __name__ == "__main__":
test_call()
test_call()
test_call()

Sample #3 Simple flask auth

import functools
from flask import Flask
from flask import request
class auth:
__name__ = "auth"
def __init__(self, f):
self.tokens = ["12345"]
def __call__(self, *args, **kwargs):
t = request.headers.get('token')
print(t)
if t not in self.tokens:
return 'Unauthenticated'
return self.func(*args, **kwargs)
app = Flask(__name__)@app.route('/hello')
def helloIndex():
return 'Hello World from Python Flask!'
@app.route('/auth_hello')
@auth
def auth_hello():
return 'Hello with token'
app.run(host='0.0.0.0', port=5000)

Browse http://localhost:5000/auth_hello without sending token

Send request with correct token will see hello message .

Sample4 pass parameters to decorator

from functools import wrapsdef post_log(level, name, message, save_result):
def inner_func(func):
@wraps(func)
def wrapper(*arg, **kwargs):
res = func(*arg, **kwargs)
res_str = res if save_result else ''
print(f'{name},{message} {res_str}')
return res
return wrapper
return inner_func
@post_log("DEBUG", "name", "message", False)
def func1():
return 1
@post_log("INFO", "name", "message", True)
def func2():
return 2
if __name__ == "__main__":
print(func1())
print(func2())

--

--

LORY
LORY

Written by LORY

A channel which focusing on developer growth and self improvement

No responses yet