6

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.

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

3 Comments

That's a nice idea but, unless I'm mistaken, what you wrote will enforce the types at runtime (i.e. dynamic type checking). I'm looking for a similar mechanism to validate the types using mypy or better - PyCharm's IDE (i.e. static type-checking / PEP 484).
Ah okay, it might be worth editing your question to be explicit with that. I can't speak for PyCharm or MyPy but type hinting is just that, hinting, so you might not find what you're after but certainly good luck!
Thank you anyway. In PyCharm the hints are actually used for code inspection (with "compiler"-warnings) so it's very useful.
1

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.