Re: Structure Pattern for annotation
I agree with Steven. I very much like Abdulla's proposed syntax for dicts, TypedDicts and sets. But I'm not sure that the idea for `Annotated` is workable, and the proposal for lists seems too prone to ambiguity, given how extensively square brackets are already used in typing syntax. One question about the proposals, however: how would we represent other mappings apart from dicts? Would `collections.abc.Mapping` and `types.MappingProxyType` still be spelled as `Mapping[str, int]` and `MappingProxyType[str, int]`? If so, that would be a slightly annoying inconsistency. I do also quite like the idea of an improved syntax for tuples specifically. Tuples are already very different types to lists/strings/etc in the context of typing, essentially representing heterogeneous structs of fixed length rather than homogenous sequences of unspecified length. As such, I think it "makes sense" to special-case tuples without special-casing other sequences such as list, `collections.abc.Sequence` or `collections.deque`. def foo() -> tuple[list[list[str]], list[list[str]]] would become def foo() -> (list[list[str]], list[list[str]]) That feels quite readable and natural, to me. Best, Alex
On 14 Oct 2021, at 09:25, Steven D'Aprano <steve@pearwood.info> wrote: On Thu, Oct 14, 2021 at 12:32:57AM +0400, Abdulla Al Kathiri wrote:
Today I found myself write a function that returns a tuple of list of list of strings (tuple[list[list[str]], list[list[str]]]). Wouldn’t it easier to read to write it like the following: ([[str]], [[str]])?
Not really. Your first example is explicit and I can get the meaning by just reading it out loud:
tuple[list[list[str]], list[list[str]]]
"tuple (of) list (of) list (of) str, list (of) list (of) str
Your abbreviated version:
([[str]], [[str]])
is too terse. I have to stop and think about what it means, not just read it out loud. Without the hint of named types (tuple and list), my first reaction to seeing [str] is "is this an optional string?".
And then I wonder why it's not written:
([[""]], [[""]])
Why abbreviate list and tuple but not string?
Code is read more than it is written, and can be too terse as well as too verbose.
On the other hand:
Similarly for TypedDict, replace the following.. class Movie(TypedDict): name: str year: int with {‘name’: str, ‘year’: int}
To my eye, that one does work. As far as I know, curly brackets {} aren't otherwise used in annotations (unlike square brackets), and they don't look like "optional" to me. They look like a dict.
So on first glance at least, I think that:
{'name': str, 'year': int}
is better than the class syntax we already have.
Likewise:
dict[str, int] will be {str: int} set[int] will be {int}.
work for me too.
Also, Annotated[float, “seconds”] can be replaced with something like float #seconds indicating whatever comes after the hashtag is just extra information similar to a normal comment in the code.
No, because the # indicates that the rest of the line is a comment. This is already legal:
def func(d: {str # this is an actual comment : int}) -> Any: ...
so this would be ambiguous between a real comment and an annotation.
Even if we agreed to change the behaviour of comments, you suggested:
func(d: {str # product label: [float] # prices from 2000 to 2015})
How is the interpreter to know that the first annotation is just
"product label"
rather than this?
"product label: [float] # prices from 2000 to 2015"
So I don't think this works.
-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/T7E54D... Code of Conduct: http://python.org/psf/codeofconduct/
I think all of this additional syntax is just a mistake. The reason is it will encourage people to not properly annotate their input types for duck typing. Some of these shortcuts might be nice for output types. But the more general trying.Mapping, typing.Sequence and friends should be preferred for input types. If terse shortcuts are available for the concrete data structure types, but not for the generic types, a lot of people are going to feel nudged to type hint their python improperly. On Thu, Oct 14, 2021, 4:54 AM Alex Waygood <alex.waygood@gmail.com> wrote:
I agree with Steven. I very much like Abdulla's proposed syntax for dicts, TypedDicts and sets. But I'm not sure that the idea for `Annotated` is workable, and the proposal for lists seems too prone to ambiguity, given how extensively square brackets are already used in typing syntax.
One question about the proposals, however: how would we represent other mappings apart from dicts? Would `collections.abc.Mapping` and ` types.MappingProxyType` still be spelled as `Mapping[str, int]` and `MappingProxyType[str, int]`? If so, that would be a slightly annoying inconsistency.
I *do *also quite like the idea of an improved syntax for *tuples *specifically. Tuples are already very different types to lists/strings/etc in the context of typing, essentially representing heterogeneous structs of fixed length rather than homogenous sequences of unspecified length. As such, I think it "makes sense" to special-case tuples without special-casing other sequences such as list, `collections.abc.Sequence` or `collections.deque`.
def foo() -> tuple[list[list[str]], list[list[str]]]
would become
def foo() -> (list[list[str]], list[list[str]])
That feels quite readable and natural, to me.
Best, Alex
On 14 Oct 2021, at 09:25, Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, Oct 14, 2021 at 12:32:57AM +0400, Abdulla Al Kathiri wrote:
Today I found myself write a function that returns a tuple of list of
list of strings (tuple[list[list[str]], list[list[str]]]). Wouldn’t it
easier to read to write it like the following:
([[str]], [[str]])?
Not really. Your first example is explicit and I can get the meaning by just reading it out loud:
tuple[list[list[str]], list[list[str]]]
"tuple (of) list (of) list (of) str, list (of) list (of) str
Your abbreviated version:
([[str]], [[str]])
is too terse. I have to stop and think about what it means, not just read it out loud. Without the hint of named types (tuple and list), my first reaction to seeing [str] is "is this an optional string?".
And then I wonder why it's not written:
([[""]], [[""]])
Why abbreviate list and tuple but not string?
Code is read more than it is written, and can be too terse as well as too verbose.
On the other hand:
Similarly for TypedDict, replace the following..
class Movie(TypedDict):
name: str
year: int
with
{‘name’: str, ‘year’: int}
To my eye, that one does work. As far as I know, curly brackets {} aren't otherwise used in annotations (unlike square brackets), and they don't look like "optional" to me. They look like a dict.
So on first glance at least, I think that:
{'name': str, 'year': int}
is better than the class syntax we already have.
Likewise:
dict[str, int] will be {str: int}
set[int] will be {int}.
work for me too.
Also, Annotated[float, “seconds”] can be replaced with something like
float #seconds indicating whatever comes after the hashtag is just
extra information similar to a normal comment in the code.
No, because the # indicates that the rest of the line is a comment. This is already legal:
def func(d: {str # this is an actual comment : int}) -> Any: ...
so this would be ambiguous between a real comment and an annotation.
Even if we agreed to change the behaviour of comments, you suggested:
func(d: {str # product label: [float] # prices from 2000 to 2015})
How is the interpreter to know that the first annotation is just
"product label"
rather than this?
"product label: [float] # prices from 2000 to 2015"
So I don't think this works.
-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/T7E54D... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YUPJNZ... Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, 14 Oct 2021 at 13:04, Ricky Teachey <ricky@teachey.org> wrote:
I think all of this additional syntax is just a mistake.
The reason is it will encourage people to not properly annotate their input types for duck typing. Some of these shortcuts might be nice for output types. But the more general trying.Mapping, typing.Sequence and friends should be preferred for input types. If terse shortcuts are available for the concrete data structure types, but not for the generic types, a lot of people are going to feel nudged to type hint their python improperly.
+1. I'm not sure how much of my reservations about this whole discussion are ultimately reservations about typing in general, but I feel that the more we make it easier to express "exact" types, the more we encourage people to constrain their APIs to take precise types rather than to work with duck types. (I saw an example recently where even Mapping was over-specified, all that was needed was __getitem__, not even __len__ or __iter__). I know protocols allow duck typing in a static type checking context - maybe the energy focused on "making basic types easier to write" should be focused on making protocols easier to write, instead. Paul
On Thu, Oct 14, 2021 at 8:46 AM Paul Moore <p.f.moore@gmail.com> wrote:
...maybe the energy focused on "making basic types easier to write" should be focused on making protocols easier to write, instead.
Paul
+ a billion Rick. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler
I love the proposal for dicts, but I agree that this discourages duck typing. Could the curly braces notation represent Mapping, not dict specifically? +1 to shortening tuples but not other sequences. -- Finn Mason On Thu, Oct 14, 2021, 6:46 AM Paul Moore <p.f.moore@gmail.com> wrote:
On Thu, 14 Oct 2021 at 13:04, Ricky Teachey <ricky@teachey.org> wrote:
I think all of this additional syntax is just a mistake.
The reason is it will encourage people to not properly annotate their
input types for duck typing. Some of these shortcuts might be nice for output types. But the more general trying.Mapping, typing.Sequence and friends should be preferred for input types. If terse shortcuts are available for the concrete data structure types, but not for the generic types, a lot of people are going to feel nudged to type hint their python improperly.
+1. I'm not sure how much of my reservations about this whole discussion are ultimately reservations about typing in general, but I feel that the more we make it easier to express "exact" types, the more we encourage people to constrain their APIs to take precise types rather than to work with duck types. (I saw an example recently where even Mapping was over-specified, all that was needed was __getitem__, not even __len__ or __iter__).
I know protocols allow duck typing in a static type checking context - maybe the energy focused on "making basic types easier to write" should be focused on making protocols easier to write, instead.
Paul _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/KALBNJ... Code of Conduct: http://python.org/psf/codeofconduct/
On Fri, Oct 15, 2021 at 1:06 PM Finn Mason <finnjavier08@gmail.com> wrote:
I love the proposal for dicts, but I agree that this discourages duck typing. Could the curly braces notation represent Mapping, not dict specifically?
+1 to shortening tuples but not other sequences.
-- Finn Mason
That might be useful. But don't forget there is also MutableMapping. --- Ricky. "I've never met a Kentucky man who wasn't either thinking about going home or actually going home." - Happy Chandler
I don’t understand why tuple structure is not supported already. It makes reading the function signature a breeze and very natural. You can also do it without parentheses which mimics the return of multiple objects often seen in functions(def func(*args: int) -> str, [int])
On 14 Oct 2021, at 12:53 PM, Alex Waygood <alex.waygood@gmail.com> wrote:
I agree with Steven. I very much like Abdulla's proposed syntax for dicts, TypedDicts and sets. But I'm not sure that the idea for `Annotated` is workable, and the proposal for lists seems too prone to ambiguity, given how extensively square brackets are already used in typing syntax.
One question about the proposals, however: how would we represent other mappings apart from dicts? Would `collections.abc.Mapping` and `types.MappingProxyType` still be spelled as `Mapping[str, int]` and `MappingProxyType[str, int]`? If so, that would be a slightly annoying inconsistency.
I do also quite like the idea of an improved syntax for tuples specifically. Tuples are already very different types to lists/strings/etc in the context of typing, essentially representing heterogeneous structs of fixed length rather than homogenous sequences of unspecified length. As such, I think it "makes sense" to special-case tuples without special-casing other sequences such as list, `collections.abc.Sequence` or `collections.deque`.
def foo() -> tuple[list[list[str]], list[list[str]]]
would become
def foo() -> (list[list[str]], list[list[str]])
That feels quite readable and natural, to me.
Best, Alex
On 14 Oct 2021, at 09:25, Steven D'Aprano <steve@pearwood.info> wrote:
On Thu, Oct 14, 2021 at 12:32:57AM +0400, Abdulla Al Kathiri wrote:
Today I found myself write a function that returns a tuple of list of list of strings (tuple[list[list[str]], list[list[str]]]). Wouldn’t it easier to read to write it like the following: ([[str]], [[str]])?
Not really. Your first example is explicit and I can get the meaning by just reading it out loud:
tuple[list[list[str]], list[list[str]]]
"tuple (of) list (of) list (of) str, list (of) list (of) str
Your abbreviated version:
([[str]], [[str]])
is too terse. I have to stop and think about what it means, not just read it out loud. Without the hint of named types (tuple and list), my first reaction to seeing [str] is "is this an optional string?".
And then I wonder why it's not written:
([[""]], [[""]])
Why abbreviate list and tuple but not string?
Code is read more than it is written, and can be too terse as well as too verbose.
On the other hand:
Similarly for TypedDict, replace the following.. class Movie(TypedDict): name: str year: int with {‘name’: str, ‘year’: int}
To my eye, that one does work. As far as I know, curly brackets {} aren't otherwise used in annotations (unlike square brackets), and they don't look like "optional" to me. They look like a dict.
So on first glance at least, I think that:
{'name': str, 'year': int}
is better than the class syntax we already have.
Likewise:
dict[str, int] will be {str: int} set[int] will be {int}.
work for me too.
Also, Annotated[float, “seconds”] can be replaced with something like float #seconds indicating whatever comes after the hashtag is just extra information similar to a normal comment in the code.
No, because the # indicates that the rest of the line is a comment. This is already legal:
def func(d: {str # this is an actual comment : int}) -> Any: ...
so this would be ambiguous between a real comment and an annotation.
Even if we agreed to change the behaviour of comments, you suggested:
func(d: {str # product label: [float] # prices from 2000 to 2015})
How is the interpreter to know that the first annotation is just
"product label"
rather than this?
"product label: [float] # prices from 2000 to 2015"
So I don't think this works.
-- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/T7E54D... Code of Conduct: http://python.org/psf/codeofconduct/
Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YUPJNZ... Code of Conduct: http://python.org/psf/codeofconduct/
El vie, 15 oct 2021 a las 14:42, Abdulla Al Kathiri (< alkathiri.abdulla@gmail.com>) escribió:
I don’t understand why tuple structure is not supported already. It makes reading the function signature a breeze and very natural. You can also do it without parentheses which mimics the return of multiple objects often seen in functions(def func(*args: int) -> str, [int])
I brought this up before and one issue is that it's hard to distinguish between a tuple used as a type parameter and multiple type parameters:
GenericClass[(A, B)] # parameterized by the type Tuple[A, B] GenericClass[A, B] # two type parameters The ASTs for both of those are the same, so it would be difficult for mypy to distinguish them. I do agree that it would be nice to write types like ([str], [int]), but there are some practical problems.
I guess you could work around this by exploiting the slicing operator: GenericClass[:(A, B)] It makes sense to use the : in the context of typing, but I can see how this syntax can be confusing. The least confusing implementation I could think of is to limit the use of GenericClass[:_] to tuples, lists, sets and dicts (and future callable type signatures?), i.e.; it should only be used for structural type pattern matching. Here is a simple demo: https://gist.github.com/jorenham/1c241a1cf33d2cc8235631b63fa8f279
participants (7)
-
Abdulla Al Kathiri
-
Alex Waygood
-
Finn Mason
-
Jelle Zijlstra
-
Joren Hammudoglu
-
Paul Moore
-
Ricky Teachey