Compact syntax for Callable: using dicts
Hello everyone, Since PEP with new callable syntax was rejected, I would like to propose another idea. It is quite simple, but yet powerful enough for our main use-cases. We can use `Callable[{'arg_name': arg_type}, ret_type]` syntax. It is an allowed syntax and python3.10+ can work with it out of the box: ``` Python 3.10.0 (default, Nov 1 2021, 10:24:06) [Clang 11.0.0 (clang-1100.0.33.16)] on darwin
from typing import Callable Callable[{}, int] typing.Callable[[{}], int]
It supports multi-line readable format:
func: Callable[{ ... 'a': int, ... 'b': str, ... }, int]
How can it solve our main problems?
1. It clearly supports argument names: `{'arg_name': int}`
2. It can support positional only arguments via: `{'__arg_name': int}` or `{'/arg_name': int}`
3. It can support args and kwargs: `{'*': int, '**': str}`
4. It can support kw-only arguments: `{'*kw_arg': type}`
5. It can support any arguments with default values: `{'required_arg': int, 'has_default': typing.NotRequired[str]}`, because the exact default value is not a part of the function signature
This change does not require any parser changes, only semantic ones in `typing.py` and type-checkers.
Old `Callable` semantics with `[]` will stay the same.
Probably older python versions would need to use `typing_extensions.Callable` to have this feature.
Old pythons raise an error for `{}` use in `Callable`:
Python 3.7.11 (default, Jul 16 2021, 15:35:56)
from typing import Callable Callable[{}, int] Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Users/sobolev/.pyenv/versions/3.7.11/lib/python3.7/typing.py", line 760, in __getitem__ raise TypeError(f"Callable[args, result]: args must be a list." TypeError: Callable[args, result]: args must be a list. Got {}
Later we can reuse quite similar syntax for in-place typed-dict definitions:
def expects_user(user: {'email': str, 'age': int}): print(user['email'], user['age']) ``` What do other think about this idea? :)
The first question that goes through my mind is "what problem is this intended to solve?". In the many discussions that led to PEP 677 (Callable Type Syntax), we focused on the need to create an easier-to-understand syntax for the existing `Callable` type annotation. We explored whether such a syntax could be expanded to support function signature features that are not possible with today's `Callable` syntax -- features like *args/**kwargs, keyword-only parameters, and default arg values. We concluded after much discussion and an analysis of existing typed code bases that these other function signature features didn't appear frequently enough to justify burdening the new syntax with them. We decided that the existing callback protocol mechanism was sufficient to cover these use cases. The proposal requires type checkers to support an expression form (a dictionary literal) that is not currently allowed in any other type annotation, so it would require `Callable` to be special-cased. It would introduce a new annotation form where the semantics are different from anything that exists today, so developers would need to be educated about the new semantics. And it would add no new capabilities, just a redundant way to express what is already possible with a callback protocol. I see those as downsides, and I think we need to weigh those against the potential upsides. Before we create a redundant mechanism, I think we should be convinced that there is sufficient need to do so. Past discussions and analysis of code led us to conclude that there isn't much need here. Do you have new data or arguments that would suggest otherwise? If we could find new data to support the need for a redundant mechanism, then I'd want to explore alternative expression forms (other than dictionary expressions) before choosing one particular solution. For example, a list of tuple expressions might be more natural and consistent with existing type mechanisms like `NamedTuple` definitions. -Eric -- Eric Traut Contributor to Pyright & Pylance Microsoft
participants (2)
-
Eric Traut
-
Nikita Sobolev