
Oct. 8, 2021
8:02 p.m.
Thanks for summarizing the PSC position, Barry! I agree that type annotation syntax should be consistent with the rest of the language, but I'm curious why it has to be "standard Python syntax"? Could you elaborate a bit more on the reasoning behind that constraint? Cheers, Sergei On Fri, Oct 8, 2021 at 8:38 PM Barry Warsaw <barry@python.org> wrote: > Thanks for thinking more deeply about how we can make type annotations for > callables more user friendly. > > The intersection between the syntax for general Python code and type > annotations has been a topic of discussion within the Steering Council (on > and off) for quite some time. We intend to provide more clarity about our > thinking, probably in the form of an informational PEP, around this topic, > and my apologies because I haven’t had time to draft it yet. > > But since this came up, I want to at least say that we are unanimous in > our belief that the type annotation language must also be standard Python > syntax. In other words, we are not in favor of letting type annotation > syntax deviate from Python syntax. As a effect of this, the PSC does not > intend to issue a blanket delegation of type-focused PEPs. Of course, > individual typing PEPs can be delegated just like any other PEP, but > especially where syntax change proposals are made, I expect that the PSC > will want keep final decision making. > > This means that any PEP which proposes syntactic changes to support typing > features must also address the implications of those syntax changes for the > general Python language. PEP 646 (Variadic Generics) is a good example of > this. Early on we recognized that the proposed syntax change had > implications for Python, and we asked the PEP authors to address those > implications for Python, which they added: > > https://www.python.org/dev/peps/pep-0646/#grammar-changes > > This is the kind of analysis the PSC needs in order to weigh the cost and > benefits of making such changes to Python. > > TL;RA - One Syntax to Rule Them All > > Cheers, > -Barry > > > On Oct 7, 2021, at 09:41, S Pradeep Kumar <gohanpra@gmail.com> wrote: > > > > Hello all, > > > > Typing-sig has been discussing user-friendly syntax for the type used to > represent callables. [1] Since this affects the Python language syntax, we > wanted to get some high-level feedback from you before putting up a > detailed PEP. > > > > TL;DR: We want to propose syntax for Callable types, e.g., `(int, str) > -> bool` instead of `typing.Callable[[int, str], bool]`. Questions: 1. Are > there concerns we need to keep in mind about such a syntax change? 2. > Should we propose syntax for additional features in the same PEP or in a > future PEP? > > > > > > # Motivation > > > > Guido has pointed out that `Callable` is one of the most frequently used > type forms but has the least readable syntax. For example, say we have a > callback `formatter` that accepts a record and a list of permissions: > > > > ```python > > def print_purchases( > > user, > > formatter, # <-- callback > > ): > > <...> > > output = formatter(record, permissions) > > print(output) > > ``` > > > > To give it a type, we currently have to write: > > > > ```python > > from typing import Callable > > > > def print_purchases( > > user: User, > > formatter: Callable[[PurchaseRecord, List[AuthPermission]], > FormattedItem] # Hard to read. > > ) -> None: > > > > <...> > > output = formatter(record, permissions) > > print(output) > > ``` > > > > `Callable` can be hard to understand for new users since it doesn't > resemble existing function signatures and there can be multiple square > brackets. It also requires an import from `typing`, which is inconvenient. > Around 40% of the time [2], users just give up on precisely typing the > parameters and return type of their callbacks and just leave it as a blank > Callable. In other cases, they don't add a type for their callback at all. > Both mean that they lose the safety guarantees from typing and leave room > for bugs. > > > > We believe that adding friendly syntax for Callable types will improve > readability and encourage users to type their callbacks more precisely. > Other modern, gradually-typed languages like TypeScript (JS), Hack (PHP), > etc. have special syntax for Callable types. > > > > (As a precedent, PEP 604 recently added clean, user-friendly syntax for > the widely-used `Union` type. Instead of importing `Union` and writing > `expr: Union[AddExpr, SubtractExpr], we can just write `expr: AddExpr | > SubtractExpr`.) > > > > > > # Proposal and Questions > > > > We have a two-part proposal and questions for you: > > > > 1. Syntax to replace Callable > > > > After a lot of discussion, there is strong consensus in typing-sig about > adding syntax to replace Callable. So, the above example would be written > as: > > ```python > > def print_purchases( > > user: User, > > formatter: (PurchaseRecord, List[AuthPermission]) -> FormattedItem, > > ) -> None: > > > > <...> > > output = formatter(record, permissions) > > print(output) > > ``` > > This feels more natural and succinct. > > > > Async callbacks currently need to be written as > > ``` > > from typing import Callable > > > > async_callback: Callable[[HttpRequest], Awaitable[HttpResponse]] > > ``` > > > > With the new syntax, they would be written as > > ``` > > async_callback: async (HttpRequest) -> HttpResponse > > ``` > > which again seems more natural. There is similar syntax for the type of > decorators that pass on *args and **kwargs to the decorated function. > > > > Note that we considered and rejected using a full def-signature syntax > like > > ```` > > (record: PurchaseRecord, permissions: List[AuthPermission], /) -> > FormattedItem > > ```` > > because it would be more verbose for common cases and could lead to > subtle bugs; more details in [3]. > > > > The Callable type is also usable as an expression, like in type aliases > `IntOperator = (int, int) -> int` and `cast((int) -> int, f)` calls. > > > > **Question 1**: Are there concerns we should keep in mind about such a > syntax proposal? > > > > > > > > 2. Syntax for callback types beyond Callable > > > > `Callable` can't express the type of all possible callbacks. For > example, it doesn't support callbacks where some parameters have default > values: `formatter(record)` (the user didn't pass in `permissions`). It > *is* possible to express these advanced cases using Callback Protocols (PEP > 544) [4] but it gets verbose. > > > > There are two schools of thought on typing-sig on adding more syntax on > top of (1): > > > > (a) Some, including Guido, feel that it would be a shame to not have > syntax for core Python features like default values, keyword arguments, etc. > > > > One way to represent default values or optionally name parameters > would be: > > > > ``` > > # permissions is optional > > formatter: (PurchaseRecord, List[AuthPermission]=...) -> > FormattedItem > > > > # permissions can be called using a keyword argument. > > formatter: (PurchaseRecord, permissions: List[AuthPermission]) -> > FormattedItem > > ``` > > > > There are also alternative syntax proposals. > > > > (b) Others want to wait till we have more real-world experience with the > syntax in (1). > > > > The above cases occur < 5% of the time in typed or untyped code [5]. > And the syntax in (1) is forward-compatible with the additional proposals. > So we could add them later if needed or leave them out, since we can always > use callback protocols. > > > > **Question 2**: Do you have preferences either way? Do we propose (1) > alone or (1) + (2)? > > > > > > Once we get some high-level feedback here, we will draft a PEP going > into the details for various use cases. > > > > Best, > > Pradeep Kumar Srinivasan > > Steven Troxler > > Eric Traut > > > > PS: We've linked to more details below. Happy to provide more details as > needed. > > > > [1]: typing-sig thread about the proposal: > https://mail.python.org/archives/list/typing-sig@python.org/message/JZLYRAXJV34WAV5TKEOMA32V7ZLPOBFC/ > > [2]: Stats about loosely-typed Callables: > https://github.com/pradeep90/annotation_collector#typed-projects---callable-type > > [3]: Comparison and rejection of proposals: > https://www.dropbox.com/s/sshgtr4p30cs0vc/Python%20Callable%20Syntax%20Proposals.pdf?dl=0 > > [4]: Callback protocols: > https://www.python.org/dev/peps/pep-0544/#callback-protocols > > [5]: Stats on callbacks not expressible with Callable: > https://drive.google.com/file/d/1k_TqrNKcbWihRZdhMGf6K_GcLmn9ny3m/view?usp=sharing > > _______________________________________________ > > Python-Dev mailing list -- python-dev@python.org > > To unsubscribe send an email to python-dev-leave@python.org > > https://mail.python.org/mailman3/lists/python-dev.python.org/ > > Message archived at > https://mail.python.org/archives/list/python-dev@python.org/message/VBHJOS3LOXGVU6I4FABM6DKHH65GGCUB/ > > Code of Conduct: http://python.org/psf/codeofconduct/ > > _______________________________________________ > Python-Dev mailing list -- python-dev@python.org > To unsubscribe send an email to python-dev-leave@python.org > https://mail.python.org/mailman3/lists/python-dev.python.org/ > Message archived at > https://mail.python.org/archives/list/python-dev@python.org/message/4TY3MVJQOLKSTMCJRTGAZEOSIIMAWQ45/ > Code of Conduct: http://python.org/psf/codeofconduct/ >