AttributeError: 'function' object has no attribute 'register' when using functools.singledispatch

Question:

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'
Asked By: DanielBell99

||

Answers:

Functions must be uniquely named

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
Answered By: DanielBell99