I have a set of functions which all accept a value
named parameter, plus arbitrary other named parameters.
I have a decorator: lazy
. Normally the decorated functions return as normal, but return a partial function if value
is None.
How do I type-hint the decorator, whose output depends on the value input?
from functools import partialdef lazy(func): def wrapper(value=None, **kwargs): if value is not None: return func(value=value, **kwargs) else: return partial(func, **kwargs) return wrapper@lazydef test_multiply(*, value: float, multiplier: float) -> float: return value * multiplier@lazydef test_format(*, value: float, fmt: str) -> str: return fmt % valueprint('test_multiply 5*2:', test_multiply(value=5, multiplier=2))print('test_format 7.777 as .2f:', test_format(value=7.777, fmt='%.2f'))func_mult_11 = test_multiply(multiplier=11) # returns a partial functionprint('Type of func_mult_11:', type(func_mult_11))print('func_mult_11 5*11:', func_mult_11(value=5))
I'm using mypy
and I've managed to get most of the way using mypy extensions, but haven't got the value
typing working in wrapper
:
from typing import Callable, TypeVar, ParamSpec, Any, Optionalfrom mypy_extensions import DefaultNamedArg, KwArgR = TypeVar("R")P = ParamSpec("P")def lazy(func: Callable[P, R]) -> Callable[[DefaultNamedArg(float, 'value'), KwArg(Any)], Any]: def wrapper(value = None, **kwargs: P.kwargs) -> R | partial[R]: if value is not None: return func(value=value, **kwargs) else: return partial(func, **kwargs) return wrapper
How can I type value
? And better still, can I do this without mypy extensions?