In the example below, we have no real need to evaluate the type annotations of the non-dispatched args.
Skipping this might improve performance / import time a little.
While a little late for some nice features like X | Y syntax, this is useful in case we introduce new typing syntax in the future, since it allows users to use it on non-dispatched args.
@AlexWaygood suggested in #119891 (comment) that the PEP 649 changes could fix this issue too. Unfortunately, PEP 649 does not allow the example above to pass, because when you call an __annotate__ function, all the code is always evaluated, so 1/0 gets run and throws an error. The tricks that we add to support forward references work if you use undefined names, but not for other runtime errors.
The good news is that something like this (more realistic than 1/0 in an annotation) does now work on main:
fromtypingimportTYPE_CHECKINGifTYPE_CHECKING:
fromexpensiveimportSomeTypefromfunctoolsimportsingledispatch@singledispatchdeffun(arg, verbose):
return"fun"@fun.registerdef_(arg: int, verbose: SomeType):
return"int fun"fun("x", None) # funfun(1, None) # int fun
But the OP's example above will still fail. We could fix this by a solution like making __annotate__ support an optional parameter saying it should only evaluate some of the annotations. I personally feel that's not worth the effort, but I'm open to other opinions.
Activity
JelleZijlstra commented on Sep 17, 2024
@AlexWaygood suggested in #119891 (comment) that the PEP 649 changes could fix this issue too. Unfortunately, PEP 649 does not allow the example above to pass, because when you call an __annotate__ function, all the code is always evaluated, so 1/0 gets run and throws an error. The tricks that we add to support forward references work if you use undefined names, but not for other runtime errors.
The good news is that something like this (more realistic than 1/0 in an annotation) does now work on main:
But the OP's example above will still fail. We could fix this by a solution like making __annotate__ support an optional parameter saying it should only evaluate some of the annotations. I personally feel that's not worth the effort, but I'm open to other opinions.
johnslavik commented on Jan 20, 2026
This is a nuanced one. I personally don't think it's worth it as well -- it's a special case.
A potential time of revisit is when the lazy imports feature gets merged.
flying-sheep commented on Aug 13, 2026
We use singledispatch a lot with dummy classes:
For this to be replaced with lazy imports, we really do need something new.