Для произвольной функции вы вообще не можете этого сделать - здесь даже нет синтаксиса. Вот я составляю некоторый синтаксис для этого.
отрим следующий код:
from typing import Callable, Any
TFunc = Callable[..., Any]
def get_authenticated_user(): return "John"
def require_auth() -> Callable[TFunc, TFunc]:
def decorator(func: TFunc) -> TFunc:
def wrapper(*args, **kwargs) -> Any:
user = get_authenticated_user()
if user is None:
raise Exception("Don't!")
return func(*args, **kwargs)
return wrapper
return decorator
@require_auth()
def foo(a: int) -> bool:
return bool(a % 2)
foo(2) # Type check OK
foo("no!") # Type check failing as intended
Этот кусок кода работает как задумано. Теперь представьте, что я хочу расширить это, а не просто выполнятьfunc(*args, **kwargs)
Я хочу ввести имя пользователя в аргументах. Поэтому я изменяю сигнатуру функции.
from typing import Callable, Any
TFunc = Callable[..., Any]
def get_authenticated_user(): return "John"
def inject_user() -> Callable[TFunc, TFunc]:
def decorator(func: TFunc) -> TFunc:
def wrapper(*args, **kwargs) -> Any:
user = get_authenticated_user()
if user is None:
raise Exception("Don't!")
return func(*args, user, **kwargs) # <- call signature modified
return wrapper
return decorator
@inject_user()
def foo(a: int, username: str) -> bool:
print(username)
return bool(a % 2)
foo(2) # Type check OK
foo("no!") # Type check OK <---- UNEXPECTED
Я не могу найти правильный способ напечатать это. Я знаю, что в этом примере оформленная функция и возвращаемая функция должны технически иметь одинаковую подпись (но даже это не определяется).