PEP 585 extension: allowing builtin containers specified with shorthands

Hi.

PEP 585 PEP 585 – Type Hinting Generics In Standard Collections | peps.python.org introduced the feature of builtin containers, like list, tuple and set having the square-bracket operator to create a parameterized container type, e.g. list[str] instad of using typing.List[str].

This is a great feature as it allows the typing system to slowly become more and more integrated with the language.

Then I have another suggestion, which naturally extends on this feature, which is to use brackets or parenthesis inside type annotations, e.g.

def my_fun(arr: [str], tup: (int,int,int), dic:{int:str}) -> (int, {float}):
    pass

This example shows a function my_fun that accepts a list[str], a tuple[int,int,int] and a dict[int,str]. Then it returns a tuple[int, set[float]] Given these containers are being “instantiated” inside type annotations it is entirely unambiguous that they represent parameterized types.

This feature naturally comes from the cumbersome notation needed whenever a function wants to return two or more values. Currently, one has to type def my_fun(...) -> tuple[int, set[float]] which is repetitive and noisy. I’d rather simplify it to def my_fun(...) -> (int, set[float]) at least.

But I’m a bit confused about the status of this syntax as I see some tools (pycharm and mypy at least) which seem to support the -> (...) or -> [...] syntax for function return types, although both these cases are always handled as a tuple. And I can’t find anywhere in the typing PEPs any explicit mention to return with -> (...).

Anyway, this suggestion is more generic and applies to more container types and also to function arguments.

Thank you.

PS: I’ve seen mentions on github about the tuple syntax being rejected long time ago, before the first typing PEPs. But it might be worthwhile to revisit it.

PSS: I’m hope I’m not getting the terminology entirely wrong.

Most type hinting syntax discussion happens on the typing-sig mailing list.

I believe this, or very similar proposal, has been brought up multiple times but I don’t know the content well enough to quickly link you to a relevant discussion.

1 Like

It has been suggested a few times, but the main reason it has been rejected is that we don’t really want to privilege builtins like this. In many cases, annotating as a specific collection isn’t actually correct, you want a more generic interface like Mapping, Sequence, Iterable etc. In the case of lists and tuples, it’s also ambiguous in some cases - does Spam[(int, int)] mean Spam[int, int], or Spam[tuple[int, int]]? Syntactically these are identical, so runtime code cannot tell the difference. For lists the same issue would come up with Callable, ParamSpec and TypeVarTuple.

4 Likes

I don’t know about the others, but [str] in the signature of a function looks confusingly like the usage of [arg] to represent optional arguments in the docs. I would not like this to become a standard. list[str] is compact enough.

Thank you. But there seems to be many places where discussion happens, so I was not entirely sure which would be the preferred place.

How does that square then with list[str] and so forth? Did the same “privilege builtins” argument popped up ?

That is true at least for me. I often use the more generic container types as arguments to functions.

Right. I think that alone breaks the suggestion.

If it’s defined in some grammar, then it would perhaps be a problem. Else, if it is just a convention, well, that’s why people have these conversations in the first place, and I believe the syntax actually is [, arg1, arg2] (starts with a comma).


OK, so, so far people not too happy with the [{(type)}] notation.
But the other part of the proposal was to simplify returning multiple values from functions, so, this I think it still quite valid.

def my_fun(*args) -> (int, str, ...):
    pass

Thank you so far.

1 Like

There is no such thing as returning multiple values: you are returning a tuple. If we make (A, B) mean tuple[A, B], it would be confusing if that syntax works only at the top level, and not in for example list[tuple[A, B]].

1 Like

Unfortunately that won’t work consistently because there’s no guarantee that the type hint you specify can be hashed and thus used in your dict and set suggestions.