Okay, you've got me convinced. Using `*args: *blah` makes sense.On Mon, Oct 18, 2021 at 12:39 PM S Pradeep Kumar <gohanpra@gmail.com> wrote:> I can't think of any use cases either. It's super unusual in Python to have a variable number arguments followed by a fixed argument, since the function being called would have to slice args to get at it.Guido: I agree that it's unusual in regular Python code. However, it's not rare at all in Tensor code.Here's a real-world example: Tensor.view [1] infers a dimension that is specified as -1.
```>>> x = torch.randn(2, 3, 4, 5, 6)>>> y = x.view(3, 5, 2, -1)>>> y.size# the -1 gets replaced by (2 * 3 * 4 * 5 * 6) / (3 * 5 * 2) = 24# => (3, 5, 2, 24)We write this as:def view(
self: Tensor[DType, *Rs], *shape: *Tuple[*Rs2, L[-1]]
) -> Tensor[
DType, *Rs2, Divide[Product[*Rs], Product[*Rs2]]
]: ...```Full stub for Tensor.view: [2]. Another example is `torch.reshape`, which again takes `*args`.More importantly, as Eric pointed out, this is an incompleteness in function signatures. `Callable [[int, *Ts, str], None]` is allowed. But there is no way in the PEP to specify a function of that type. Thus we need to allow:```def foo(*args: *Tuple[int, *Ts, str]) -> None: ...```The type-checker implementer actually has to use the same data structure to represent the type of both the Callable type and the function `foo`, so Pyre already supports both. Whenever Pyre sees a Callable containing `*Ts`, such as `Callable[[int, *Ts, str], None]`, it basically treats it as a function with `*args: *Tuple[int, *Ts, str]`.If the objection is that we would be calling `*` on something other than a `Ts`, note that in the future we'll also need to unpack Map, Broadcast, etc. The consistent solution here is to allow unpacking of any tuple.[1]: Tensor.view: https://pytorch.org/docs/stable/generated/torch.Tensor.view.html?highlight=view#torch.Tensor.view(The actual question on python-dev was about Map, as Guido said, but that and Eric's question to me earlier brought up the above point.)On Thu, Oct 14, 2021 at 12:12 PM Guido van Rossum <guido@python.org> wrote:I can't think of any use cases either. It's super unusual in Python to have a variable number arguments followed by a fixed argument, since the function being called would have to slice args to get at it.But I thought the post on python-dev that you linked to was about something else?It uses the builtin function enumerate(), which takes an iterable of values like ['x', 'y', 'z'] and turns it into a stream of pairs (0, 'x'), (1, 'y'), (2, 'z').It then defines a function enumerate_args(f, args) which calls f(*enumerate(args)), i.e. if args has length N, then f takes N arguments, each of which has type Tuple[int, T] where T is the item type of args.In my example ['x', 'y', 'z'], N is 3 and T is str, so enumerate_args(f, ['x', 'y', 'z']) will end up calling f((0, 'x'), (1, 'y'), (2, 'z'). I guess the type of f is then (*args: Tuple[int, T]) ->None but this doesn't capture the length of args, N. The response on python-dev indicates that the solution requires Map[].But maybe I've missed the connection between that post and your idea of allowing *args, *Tuple[*Ts, int] in a parameter list?On Thu, Oct 14, 2021 at 5:05 AM Matthew Rahtz via Typing-sig <typing-sig@python.org> wrote:In the last tensor typing meeting we realised there's something missing from PEP 646: the ability to split off suffixes from *args. (Thanks for Pradeep for pointing this out, based on discussions with Eric Traut and this question on python-dev https://mail.python.org/archives/list/python-dev@python.org/thread/K76H6C5JWGJ7TW6DGOCZGOTVONWOFCWD/#YBJXIAGODKH4NB5OD4YBZUZPA7NV6T73)_______________________________________________IntroTo recap, PEP 646 allows us to bind the types of *args into a TypeVarTuple:Ts = TypeVarTuple('Ts')def foo(*args: *Ts): ...foo(1, '2') # Ts is bound to Tuple[int, str]But what if we wanted to do something like the following?def foo(*args: [types of all positional args but the last bound to Ts; type of last positional arg should be int]) -> Tuple[*Ts]: ...x = foo(True, 1.0, 2) # x should have type Tuple[bool, float]The problemYou might think the answer is:def foo(*args: *Ts,final_arg: int,) -> Tuple[*Ts]: ...But note that this means something different; all arguments after *args must be specified as keywords:> foo(True, 1.0, 2)TypeError: foo() missing 1 required keyword-only argument: 'final_arg'Note that this is an only an issue for suffixes of variadic argument lists; prefixes are fine:def foo(first_arg: int,*args: *Ts,) -> Tuple[*Ts]: ...Proposed solutionWe think the way of encoding what we want most consistent with the rest of PEP 646 would be something like:def foo(*args: *Tuple[*Ts, int],) -> Tuple[*Ts]: ...Why? Well, when we say `*args: *Ts`, we're saying "Put all the types of `args` into the thing that comes after the starred part of the annotation". So here, we're saying "Put all the types of `args` into Tuple[*Ts, int]" - that is, doing some pattern matching, "Put all types but the last into `Ts`".Use cases?This is (for me) an unintuitive enough construction that I think our first question should be, does this have plausible enough use cases to support the complexity?The only one I can think off of the top of my head is something like:def log_with_logger(*args: *Tuple[*Ts, Logger]): ...log_with_logger('foo', 'bar', logger_inst)But here the issue could be worked around by just moving the position of the logger argument:def log_with_logger(logger: Logger, *args: *Ts): ...So I'm not sure I really believe this example.Can anyone else think of any use cases for this?---Thanks!Matthew
Typing-sig mailing list -- typing-sig@python.org
To unsubscribe send an email to typing-sig-leave@python.org
https://mail.python.org/mailman3/lists/typing-sig.python.org/
Member address: guido@python.org
--_______________________________________________--Guido van Rossum (python.org/~guido)Pronouns: he/him (why is my pronoun here?)
Typing-sig mailing list -- typing-sig@python.org
To unsubscribe send an email to typing-sig-leave@python.org
https://mail.python.org/mailman3/lists/typing-sig.python.org/
Member address: gohanpra@gmail.com
--S Pradeep Kumar
----Guido van Rossum (python.org/~guido)Pronouns: he/him (why is my pronoun here?)