Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Union of ParamSpec? #17481

Open
JulienPalard opened this issue Jul 4, 2024 · 1 comment
Open

Union of ParamSpec? #17481

JulienPalard opened this issue Jul 4, 2024 · 1 comment
Labels

Comments

@JulienPalard
Copy link
Member

Feature

Currently it's possible to concatenate a type to a paramspec to get a new paramspec.

I think I may need the ability to concatenate two paramspecs, like:

P = ParamSpec('P')
Q = ParamSpec('Q')
R = TypeVar("R")
Callable[Concatenate[P, Q], R]

Pitch

I'm trying to describe partial-like functions, I spotted #16939 which solves if for functools.partial (which is good) but still not giving a way to describe other partial-like functions.

Currently I can successfully describe the "removal" of one or multiple parameters:

from collections.abc import Callable
from typing import Concatenate, Generic, ParamSpec, TypeVar

P = ParamSpec('P')
Q = ParamSpec('Q')
S = TypeVar('S')
T = TypeVar('T')
U = TypeVar('U')


def substract_one_parameter(given: T, func: Callable[Concatenate[T, P], U]) -> Callable[P, U]:
    def inner(*args: P.args, **kwargs: P.kwargs) -> U:
        return func(given, *args, **kwargs)
    return inner


def substract_two_parameters(first: S, second: T, func: Callable[Concatenate[S, T, P], U]) -> Callable[P, U]:
    def inner(*args: P.args, **kwargs: P.kwargs) -> U:
        return func(first, second, *args, **kwargs)
    return inner


def int_int_int(a: int, b: int) -> int:
    return a + b


c = substract_one_parameter(1, int_int_int)
reveal_type(c)  # def (b: builtins.int) -> builtins.int
print(c(2))


d = substract_two_parameters(1, 2, int_int_int)
reveal_type(d)  # def () -> builtins.int
print(d())

But what I think I need is:

# P are the "removed" parameters
# Q are the "kept" parameters
def substract_n_parameters(func: Callable[Concatenate[P, Q], U], *outer_args: P.args, **outer_kwargs: P.kwargs) -> Callable[Q, U]:
    def inner(*args: Q.args, **kwargs: Q.kwargs) -> U:
        return func(*outer_args, *args, **outer_kwargs, **kwargs)
    return inner

I feel that would cleanly express the "removal" of P from [P, Q], without the need to introduce a new function like Difference[P, Q].

I feel like this could also be used for the real functools.partial, maybe simplifying the current (working, yeah) implementation.

@mantasu
Copy link

mantasu commented Jul 24, 2024

Indeed, it would be great to have this feature:

def func[**P1, **P2, T](func1: Callable[P1, T], func2: Callable[P2, None]) -> Callable[Concatenate[P1, P2], T]: ...

Currently, as in PEP 612, Concatenate only allows a single ParamSpec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants