Skip to content

Instantly share code, notes, and snippets.

@tedkim97
Last active January 5, 2021 17:03
Show Gist options
  • Save tedkim97/32e4ce8d371d2d726ba26b1a556f4790 to your computer and use it in GitHub Desktop.
Save tedkim97/32e4ce8d371d2d726ba26b1a556f4790 to your computer and use it in GitHub Desktop.
Function decorators I use while writing/debugging code.

What is this?

These are common function decorators I use when writing, testing, or debugging Python code. If you have an incredibly complex codebase, I recommend using something like a python IDE.

Usage

Import the python module and use the @ syntax to decorate functions.

Example 1:

If I have a model that takes a long time to train, I send a notification to my email when the function is done running like this:

import decorators as dec

def send_email(username, pw, api_key, msg):
    sess = authenticate(username, pw, api_key)
    sess.send_email(msg)
    
@dec.post_exec(lambda : send_email('username', 'password', 'api_key', 'done'))
def train():
    # Takes a long time to train
    # Will send email when done

If don't like arbitrary "thunk" patterns, you can do something like this:

import decorators as dec

@dec.post_exec(send_email, 'username', 'password', 'api_key', 'done')
def train():
    # Takes a long time to train
    # Will send email when done

Example 2:

If we need to see the outputs of a function, instead of writing something like this:

def test_func(index, str1, str2):
    # do something
    
out1 = test_func(0, "abc", "def")
out2 = test_func(2, "cds", "asda")
out3 = test_func(100, "foo", "bar")
print(out1)
print(out2)
print(out3)
>> foo
>> bar
>> baz

we can do this:

import decorators as dec

@dec.print_output
def test_func(index, str1, str2):
    # do something
    
out1 = test_func(0, "abc", "def")
out2 = test_func(2, "cds", "asda")
out3 = test_func(100, "foo", "bar")
>> foo
>> bar
>> baz
import functools
import warnings
import time
# print the output of func
def print_output(func):
@functools.wraps(func)
def pout(*args, **kwargs):
output = func(*args, **kwargs)
print(f"{func.__name__} output = {output}")
return output
return pout
# print the arguments passed into func
def print_arg(func):
@functools.wraps(func)
def parg(*args, **kwargs):
print(f"function={func.__name__}; args={args}; keyword_arg={kwargs}")
return func(*args, **kwargs)
return parg
# use print_arg and print_output to display function information
def debug(func):
@functools.wraps(func)
def debug(*args, **kwargs):
return print_arg(print_output(func))(*args, **kwargs)
return debug
# Execute endExec at the end of func's execution
def post_exec(endExec):
if(not callable(endExec)):
warnings.warn("The argument is not callable")
def decorator_execute(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
output = func(*args, **kwargs)
endExec()
return output
return wrapped
return decorator_execute
# Execute endExec with argument *eargs and **keargs at the end of func's execution
def post_exec_complex(endExec, *eargs, **keargs):
if(not callable(endExec)):
warnings.warn("The argument is not callable")
def decorator_execute(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
output = func(*args, **kwargs)
endExec(*eargs, **keargs)
return output
return wrapped
return decorator_execute
# Time a function using the perf_counter which will include time elapsed during sleep
def time_pc(func=None, *, ret=False):
if func is None:
return functools.partial(time_perf_counter, ret=ret)
@functools.wraps(func)
def time_pf(*args, **kwargs):
start = time.perf_counter()
output = func(*args, **kwargs)
end = time.perf_counter()
if(ret):
return (output, end - start)
print(end-start)
return output
return time_pf
# Time a function using the process_time which will exclude time elapsed during sleep
def time_tp(func=None, *, ret=False):
if func is None:
return functools.partial(time_perf_counter, ret=ret)
@functools.wraps(func)
def time_pt(*args, **kwargs):
start = time.process_time()
output = func(*args, **kwargs)
end = time.process_time()
if(ret):
return (output, end - start)
print(end - start)
return output
return time_pt
# delay the execution of a function
def delay(duration):
def decorator_execute(func):
@functools.wraps(func)
def wrapped(*args, **kwargs):
time.sleep(duration)
return func(*args, **kwargs)
return wrapped
return decorator_execute
# print the numpy ndarray datatype and shape
# note that func must return a numpy array.
def numpy_debug(func):
@functools.wraps(func)
def np_debug(*args, **kwargs):
output = func(*args, **kwargs)
print(output.dtype, output.shape)
return output
return np_debug
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment