# -*- coding: utf-8 -*-
# @Author: cody kochmann
# @Date: 2017-12-16 10:14:56
# @Last Modified time: 2017-12-16 12:15:02
from functools import wraps
def overload(fn):
'''
This function decorator allows you to overload already defined functions. The
execution of overloaded functions is done by trying the newest version first
and if it fails, that function's predecessor will be ran.
While this does seem like a sloppy way to go about choosing the execution of
functions, this gives you far more control in terms of how you want each
function to be selected.
This approach rewards funtions that are designed with proper input validation,
which you should be adding anyways.
#------------------------------------------------------------------------------
# Example Usage Below
#------------------------------------------------------------------------------
def my_print(arg):
print('running original my_print')
print(arg)
@overload
def my_print(arg):
assert type(arg) == list
print('running list my_print')
print(', '.join(str(i) for i in arg))
@overload
def my_print(arg):
assert type(arg) == dict
print('running dict my_print')
out = ('='.join((str(k), str(v))) for k,v in arg.items())
print(' | '.join(out))
my_print(list(range(10)))
# running list my_print
# 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
my_print(tuple(range(10)))
# running original my_print
# (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
my_print({i:i*2 for i in range(10)})
# running dict my_print
# 0=0 | 1=2 | 2=4 | 3=6 | 4=8 | 5=10 | 6=12 | 7=14 | 8=16 | 9=18
'''
@wraps(fn)
def wrapper(*args, **kwargs):
try:
return fn(*args, **kwargs)
except:
return wrapper.function_to_overload(*args, **kwargs)
# attach the old version to wrapper so wrapper can reference it
wrapper.function_to_overload = fn.__globals__[fn.__name__]
# this returns true if the input has an empty docstring
has_empty_doc = lambda fn:getattr(fn, '__doc__', None) in {None, ''}
# inherit the original overloaded function's documentation if fn doesn't have one
if has_empty_doc(wrapper) and not has_empty_doc(wrapper.function_to_overload):
# None is the python standard value for no doc string
wrapper.__doc__ = getattr(wrapper.function_to_overload, '__doc__', None)
# do some cleanup
del has_empty_doc
# return the output
return wrapper