Reputation: 1834
Is there a way to have a TypeVar
(or some other format) capture all the arguments of a function? For example, say I want to wrap a general function, such that all its arguments are given within a tuple:
def invoke(f: Callable[..., T], args: Tuple[...]) -> T:
return f(*args)
Only that instead of the ellipsis (...
), I'll have the static-type inspection enforce the contents of the Tuple
to be have the same types as the function's arguments.
Thanks.
Upvotes: 6
Views: 1174
Reputation: 89139
Since Python 3.12, the syntax is simplified with type parameter lists so that it is no longer necessary to explicitly use TypeVar
or ParamSpec
here.
from collections.abc import Callable
def invoke[R, **P](f: Callable[P, R], *args: P.args, **kwargs: P.kwargs) -> R:
return f(*args, **kwargs)
Upvotes: 1
Reputation: 1834
The answer is Yes, just not with TypeVar
. One should use ParamSpec
:
from typing import ParamSpec, TypeVar, Callable
P = ParamSpec('P')
RT = TypeVar('RT')
def invoke(f: Callable[P, RT], args: P.args) -> RT:
return f(*args)
# Or, makes more sense:
def invoke(f: Callable[P, RT], args: P.args, **kwargs: P.kwargs) -> RT:
return f(*args, **kwargs)
Note that for python < 3.10, one should import it from typing_extensions
rather than typing
.
Upvotes: 2
Reputation: 3585
You could modify the below to work with your requirements, you'll likely need to add in extra handling.
from typing import Any
class TypeEnforce:
def __init__(self, func):
self.func = func
def __call__(self, *args):
types = dict(zip(self.func.__annotations__.values(), args))
for k, v in types.items():
if k is Any:
continue
assert type(v) == k
self.func(*args)
Example
@TypeEnforce
def my_test(x: str, y: int) -> None:
print(f"'x' is a {type(x).__name__}")
@TypeEnforce
def my_other_test(x: Any):
return x
my_test("Test", "eight")
my_other_test("Test2")
Will result in an AssertionError
because the function my_test
takes (str
, int
) but is passed (str
, str
). There would also be edge cases where a hint of TypedDict
would always fail because it isn't really a type, rather syntactic sugar for a dict
.
Upvotes: 1