functools.singledispatch
doesn’t currently allow dispatching on arguments that are themselves types/classes. E.g. if we try to do this:
from functools import singledispatch
@singledispatch
def describe(x) -> str:
raise TypeError(f"no description for {repr(x)}")
@describe.register(type[int])
def _(x: type[int]) -> str:
return "the integer type"
print(describe(int))
we only get back an exception:
Traceback (most recent call last):
File "example.py", line 7, in <module>
@describe.register(type[int])
File "/usr/lib/python3.10/functools.py", line 862, in register
raise TypeError(
TypeError: Invalid first argument to `register()`: type[int]. Use either `@register(some_class)` or plain `@register` on an annotated function.
For completeness’s sake, not much changes if we try to leave out the argument for register
and let singledispatch
use the annotation alone:
Traceback (most recent call last):
File "example.py", line 8, in <module>
def _(x: type[int]) -> str:
File "/usr/lib/python3.10/functools.py", line 873, in register
raise TypeError(
TypeError: Invalid annotation for 'x'. type[int] is not a class.
I would like to propose that this should be possible, considering we can use type[X]
(or Type[X]
) annotations to refer to a subtype of X
in other contexts. This would just make the behavior of singledispatch
consistent with that.
I hope this consistency argument alone is convincing enough, but if anyone insists, I can post some (admittedly fairly far-fetched) use cases for this.
I also don’t think it would be particularly difficult to implement. A proof-of-concept patch that makes the example above work can be found here, although it would need some work to make it play nicely with Union
types and Type
instead of type
, figure out if we really want to use type[X]
for register
’s argument as well or come up with a solution that doesn’t require us to put an annotation into “actual” code, optimize it, make it look nicer, and so on. But I’d be willing to look into all that and turn it into a proper PR if there is an agreement that this would be a good feature to have and I didn’t miss any reasons why this can’t actually work.