Function Overloading for Types
Description:
Typed Function overloading
Python is a very flexible language, however one thing it does not allow innately, is the overloading of functions. (With a few exceptions). For those interested, this existing kata explores the possibility of overloading object methods for different amounts of arguments. In this kata we are going to implement a form of overloading for any function/method, based on the classes of arguments, using decorators.
Overview
You will be writing a decorator @overload(*types)
that will allow a function or method to be defined multiple times for different combinations of types of input arguments. The combination and order of classes of the arguments should call a specific defined function.
To keep this kata relatively simple, various aspects of functions (Going out of scope, etc) will not be tested, more details on what will and won't be tested are listed below.
Basic Example
int)
def analyse(x):
print('X is an int!')
(list)
def analyse(x):
print('X is a list!')
analyse([]) # X is a list!
analyse(3) # X is an int!
(
Additional Information:
The decorator
- It should accept any type or class, even user made classes. Note that an inherited class does NOT count as its parent class. Each custom class should be considered unique.
- It should be able to handle any number of arguments, including zero.
- If an overloaded function/method is called without a matching set of types/classes, an Exception should be raised.
- The decorator can be used on regular functions and on instance methods of a class as well (see below about overloading vs overwritting behaviours). 'Magic methods' (eg.
__init__
,__call__
) will NOT be tested.
The decorated function or method
- The function/method should return correct values.
- All other usual function behaviours should work (Recursion, passing function as argument, etc).
- Static and class methods will NOT be tested.
- Note that when decorating an instance method, the type of
self
isn't provided to the decorator. The decorated function should yet be able to use the reference toself
. - Varargs (
*args
) may be used in functions definitions. In that case, trust the types given to the decorator to decide what call must be mapped to that function. - You do not need to consider scope problems, like having 2 different functions with the same name but in 2 different scope. All functions will be defined as top level functions, or top level object methods.
Overloading vs overwritting behaviours
- Multiple different overloaded functions/methods must be able to exist at a time:
func(int,list)
overloads a previousfunc(list)
and doesn't overwrite it. - Functions and methods should be considered distinct, ie.
analyse(int)
andmy_obj.analyse(int)
are not the same and one shouldn't overwrite the other. - If a function/method with a "known" name is decorated again with an already existing types combination, the previous definition should be overwritten (See examples below).
More specific Examples
Should accept any class or type. Variable length args should work:
class My_Class: pass
class My_Inherited_Class(My_Class): pass
(int, My_Class, str)
def some_function(*args):
return 'Option 1'
()
def some_function():
return 'Option 2'
A = My_Class()
B = My_Inherited_Class()
some_function() # Option 2
some_function(3, A, 'Words') # Option 1 <= trust the types given to the decorator
some_function('oops!') # Exception raised <= no matching types combination
some_function(3, B, 'Words') # Exception raised <= doesn't consider inheritence
Should be able to manage functions AND methods:
int)
def spin(x):
return x*3-1
(str)
def spin(x):
return x[1:] + x[0]
print(spin(6)) # 17
print(spin('Hello')) # elloH <= overload correctly, just like before...
print(spin('')) # raise IndexError
class T:
def __init__(self, x):
self.val = x
(int)
def spin(self, x):
return self.val * x
(str)
def spin(self, x):
return x + str(self.val)
obj = T(7)
print(spin(6)) # 17 <= the instance method doesn't overwrite the function
print(obj.spin(2)) # 14 <= `self` is still usable
print(spin('Hello')) # elloH
print(obj.spin('Hello')) # Hello7
(
Previous definitions should be overwritten:
str)
def upgrade(x):
print('First')
(str)
def upgrade(x):
print('Second')
upgrade('Y') # Second
(
Good luck, and I hope you enjoy the Kata!
Similar Kata:
Stats:
Created | Feb 11, 2021 |
Published | Feb 12, 2021 |
Warriors Trained | 492 |
Total Skips | 12 |
Total Code Submissions | 804 |
Total Times Completed | 97 |
Python Completions | 97 |
Total Stars | 39 |
% of votes with a positive feedback rating | 91% of 33 |
Total "Very Satisfied" Votes | 28 |
Total "Somewhat Satisfied" Votes | 4 |
Total "Not Satisfied" Votes | 1 |
Total Rank Assessments | 4 |
Average Assessed Rank | 5 kyu |
Highest Assessed Rank | 3 kyu |
Lowest Assessed Rank | 8 kyu |