Better Syntax for Type Annotations

I’m not even sure if the language would lend itself to this because types are also runtime values, but I was just wondering if it would ever be possible to get better syntax for type declarations like:

Name Current Proposed
lists list[int] int[]
tuples tuple[int, int] int, int
typed dicts class MyDict(TypedDict): x: NotRequired[int]; y: str { "x"?: int, "y": str }
literals Literal[1, 2, 3] 1 | 2 | 3
functions Function[[int, int], int] def(int, int) -> int

These aren’t meant to be perfect or exhaustive, I was mostly just interested if something like this would be possible and if anybody else would like something like this.

3 Likes

For most of those, no. Some of those could be possible.

Starting with the ones that aren’t possible:

your proposed options for lists and literals aren’t possible (they introduce ambiguity in some places, and are subject to issues when it comes to runtime introspective use). If python did not allow introspection of annotations and committed to annotations only being for type hints, these would be possible.

A quick way to see one of the issues with these:

>>> import inspect
>>> def foo(x: 1 | 2 | 3):
...     ...
>>> inspect.get_annotations(foo)
{'x': 3}

Annotations are not restricted to typing-use only, intentionally so, and are evaluated expressions.

int[] runs into colliding with existing syntax for generics, and doesn’t appear to be an improvement, only an attempt to make this have the same syntax as another language, without having the same semantics to match.

The function one (well, one very similar) was explicitly rejected by the steering council before.

The tuple case (and several other tuple cases) have been discussed before, though the issues with that one are more involved with parsing ambiguity.

The typed dict one might be possible, but there were issues with it (pyright used to have experimental support for a similar syntax)

As for these being better, the only one that actually improves something is the function one, but even this has issues as-is, and should not use def (it might be possible to make this one happen, restricted to type alias statements)

4 Likes

The callable one is similar to the rejected PEP 677

And I expect most of these would be rejected for similar reasons.
Any new syntax that is introduced cannot be typing only, since the core developers want to avoid having a typing only mini language.

The tuple and literal ones are not new syntax but would cause ambiguity in many cases, specially when doing runtime introspection.

2 Likes

Yeah, that makes sense, that’s why I thought it was probably a no-go. I clarified my original post a bit.

I guess better is a bit subject, I find myself wanting the tuple one a lot for typing function returns. The dict one might be nice, but I normally use dataclasses for typed heterogeneous records instead.

It’s impossible because x[int, str] is equivalent to x[(int, str)], which would be x[tuple[int, str]] under that proposal.

(It would have been nice if we could go back in time and make a[x, y] call a.__getitem__(x, y).)

1 Like

Yeah, it would have been nice if tuples required explicit brackets (x, y).

There is a possible migration path to add a new dunder with a changed signature, which might also be beneficial to other users, but someone would need to spend a lot of energy and time on just this single point. (Writing a PEP, finding a core dev sponsor and convincing other core devs that this is worth it)

1 Like

The main problem is that a lot of people use parentheses here:
>276k files with parentheses: a[(b, c)]
Which makes it difficult to change the behaviour.

I’m not willing to pursue this as the chance is very low that this will be accepted.

  • I like the int[] one, however I also think list[int] is understood much more easily and its still short.

  • Having a short-hand notation for typed dicts is something that I would welcome, like:

my_dict : { "x"?: int, "y": str }`
# or 
type my_dict = { "x"?: int, "y": str }
# even without the '?'
type my_dict = { "x" : NotRequired[int], "y": str }
1 Like

Yeah, without the ? it would be more consistent with “no special syntax for types”.