Goal: create a single-dispatch generic function; as per functools documentation.
I want to use my_func()
to calculate dtypes: int
or list
, in pairs.
Note: I've chosen to implement type hints and to raise errors for my own test cases, outside of the scope of this post.
For many argument data type hints; this post uses many @my_func.register(...)
decorators.
Code:
from functools import singledispatch
from typeguard import typechecked
from typing import Union
@singledispatch
@typechecked
def my_func(x, y):
raise NotImplementedError(f'{type(x)} and or {type(y)} are not supported.')
@my_func.register(int)
def my_func(x: int, y: int) -> Union[int, str]:
try:
return round(100 * x / (x + y))
except (ZeroDivisionError, TypeError, AssertionError) as e:
return f'{e}'
@my_func.register(list)
def my_func(x: list, y: list) -> Union[int, str]:
try:
return round(100 * sum(x) / (sum(x) + sum(y)))
except (ZeroDivisionError, TypeError, AssertionError) as e:
return f'{e}'
a = my_func(1, 2)
print(a)
b = my_func([0, 1], [2, 3])
print(b)
(venv) me@ubuntu-pcs:~/PycharmProjects/project$ python3 foo/bar.py
/home/me/miniconda3/envs/venv/lib/python3.9/site-packages/typeguard/__init__.py:1016: UserWarning: no type annotations present -- not typechecking __main__.my_func
warn('no type annotations present -- not typechecking {}'.format(function_name(func)))
Traceback (most recent call last):
File "/home/me/PycharmProjects/project/foo/bar.py", line 22, in <module>
@my_func.register(list)
AttributeError: 'function' object has no attribute 'register'
Credit to @Bijay Regmi for pointing this out.
@typechecked
is placed above only the polymorphed @my_func.register
functions; not above the @singledispatch
function.
Note: you still invoke my_func()
; I am just testing the polymorphed functions.
from functools import singledispatch
from typeguard import typechecked
from typing import Union
@singledispatch
def my_func(x, y):
raise NotImplementedError(f'{type(x)} and or {type(y)} are not supported.')
@my_func.register(int)
@typechecked
def my_func_int(x: int, y: int) -> Union[int, str]:
try:
return round(100 * x / (x + y))
except (ZeroDivisionError, TypeError, AssertionError) as e:
return f'{e}'
@my_func.register(list)
@typechecked
def my_func_list(x: list, y: list) -> Union[int, str]:
try:
return round(100 * sum(x) / (sum(x) + sum(y)))
except (ZeroDivisionError, TypeError, AssertionError) as e:
return f'{e}'
a = my_func_int(1, 2)
print(a)
b = my_func_list([0, 1], [2, 3])
print(b)
(venv) me@ubuntu-pcs:~/PycharmProjects/project$ python3 foo/bar.py
33
17