Код: Выделить всё
def accepts_foo(foo: int): ...
def accepts_bar(bar: int): ...
decorator_foo = DecoratorFactory(foo=1)
decorator_foo(accepts_foo) # okay because they both accept foo
decorator_foo(accepts_bar) # type error because the params are different.
Ближе всего получилось:
Код: Выделить всё
from __future__ import annotations
from typing import Callable, Generic, ParamSpec, TypeVar
from typing_extensions import reveal_type
T = TypeVar("T", covariant=True)
P = ParamSpec("P")
_NOT_SET = object()
class _Decorator(Generic[P, T]):
def __init__(self, f: Callable[P, T]) -> None:
self.f = f
self._result: T = _NOT_SET # type: ignore
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
result = self.f(*args, **kwargs)
self._result = result
return result
@property
def result(self) -> T:
assert self._result is not _NOT_SET
return self._result
class _DecoratorFactory(Generic[P]):
def __init__(self, *a: P.args, **k: P.kwargs) -> None:
self.a = a
self.k = k
def __call__(self, func: Callable[P, T]) -> _Decorator[P, T]:
return _Decorator(func)
class DecoratorFactoryFactory(Generic[P]):
def __init__(self) -> None:
pass
def __call__(self, *a: P.args, **k: P.kwargs) -> _DecoratorFactory[P]:
return _DecoratorFactory(*a, **k)
def accepts_foo(foo: int) -> float: ...
def accepts_bar(bar: int) -> str: ...
DecoratorFactory = DecoratorFactoryFactory()
decorator_foo = DecoratorFactory(foo=1)
accepts_foo = decorator_foo(accepts_foo)
reveal_type(accepts_foo(42))
reveal_type(accepts_foo.result)
accepts_bar = decorator_foo(accepts_bar)
reveal_type(accepts_bar(42))
reveal_type(accepts_bar.result)
pyright:
Код: Выделить всё
$ pyright so.py
/so.py
/so.py:54:13 - information: Type of "accepts_foo(42)" is "float"
/so.py:55:13 - information: Type of "accepts_foo.result" is "float"
/so.py:58:13 - information: Type of "accepts_bar(42)" is "str"
/so.py:59:13 - information: Type of "accepts_bar.result" is "str"
0 errors, 0 warnings, 4 informations
Подробнее здесь: https://stackoverflow.com/questions/797 ... d-function