I would see support of all argument kinds support in any proposal for a new callable: positional only args, named args, keyword-only, *args and **kwargs.
The exact notation in probably less important than missing functionality.

On Sat, Nov 28, 2020, 18:50 Abdulla Al Kathiri <alkathiri.abdulla@gmail.com> wrote:

I don’t know if this has been discussed before. 

Similar to PEP 645 idea of writing "Optional[type]" as “type?”, I propose we write "Callable[[type1, type2, ...], type3]” as “[type1, type2, … -> type3]”. Look at the two examples below and see which one looks better to the eyes:

def func1(f: typing.Callable[[str, int], str], arg1: str, arg2: int) -> str:
return f(arg1, arg2)

def func2(f: [str, int-> str], arg1: str, arg2: int) -> str:
return f(arg1, arg2)

There is less clutter especially if we have nested Callables.

e.g., f: Callable[[str, int], Callable[[int,…], str]] becomes f: [str, int -> [int, ... -> str]]

Callable without zero arguments.. f: Callable[[], str] would become f: [ -> str] 

Equivalent to Callable alone without caring about arguments and the return value would be [… -> typing.Any] or [… -> ] 

Let’s say we have a function that accepts a decorator as an argument. This might not be useful to do, but I want to show case how it would be easier to read. The old way would be:

def decorator(f: Callable[…, int]) -> Callable[…, tuple[int, str]]:
def wrapper(*args, **kwargs) -> tuple[int, str]:
text = “some text”
res = f(*args, **kwargs) 
return res, text 
return wrapper 


def function(decorator: Callable[[Callable[…, int]], Callable[…, tuple[int, str]]], decorated_on: Callable[…, int]) -> Callable[…, tuple[int, str]]:
wrapper = decorator(decorated_on) 
return wrapper 

The new way is as follows: 

def decorator(f: [… -> int]) -> [… -> tuple[int, str]]:
def wrapper(*args, **kwargs) -> tuple[int, str]:
text = “some text”
res = f(*args, **kwargs) 
return rest, text 
return wrapper 

def function(decorator: [ [… -> int] -> [… -> tuple[int, str]]], decorated_on: [… -> int]) -> [… -> tuple[int, str]]:
wrapper = decorator(decorated_on) 
return wrapper 


I saw something similar in Pylance type checker (VSC extension) when you hover over an annotated function that has Callable as an argument or a return value, but they don’t seem to use brackets to mark the beginning and end of the callable, which could be hard to follow mentally (see screenshot below)


Personally, I think it would be easier if Pylance wrote the hint like the following:

(function) function: (decorator: [p0:[*args: Any, **kwargs: Any -> int ]] -> [*args: Any, **kwargs: Any -> tuple[int, str]], decorated_on: [*args: Any, **kwargs: Any -> int]) -> [*args: Any, **kwargs: Any -> tuple[int, str]]





_______________________________________________
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/LRUXIJXCY5J274MWWNKLARB3R6UOPCUM/
Code of Conduct: http://python.org/psf/codeofconduct/