El mié, 16 jun 2021 a las 11:42, Guido van Rossum (<guido@python.org>) escribió:
On Wed, Jun 16, 2021 at 11:29 AM Jelle Zijlstra <jelle.zijlstra@gmail.com> wrote:
I would favor a shorthand where a bare name means a typed positional-only argument. That means we both get a nice shorthand (e.g., `(int, str) -> int` corresponds to `Callable[[int, str], int]`) and full power to represent all signatures (you can write `(a: int, /, b: str, *, c: int = ...) -> int` if you really need it).

El mié, 16 jun 2021 a las 11:06, Guido van Rossum (<guido@python.org>) escribió:
[...]
Additionally, what are the concerns with allowing a hybrid of named and unnamed params, ie.:

 

f: (int, str, *, foo: int = ..., **kwargs: str) -> bool


If we were to allow this, it'd be harder to give a simple rule for when the argument names can be omitted or not -- for example would we allow this?

f: (int, name: str) -> bool
This would be shorthand for a function that takes a positional-only argument of type int and a positional-or-keyword argument named "name" of type str.

But if you spell that out, you'd have to add a /, i.e.

def f(unused: int, /, name: str) -> bool: ...

I would prefer to use a simpler rule:

- Either there are *no* colons, stars, slashes or equal signs, and then it's a bunch of positional-only args given by type; example: (int, str) -> bool.

- Or the argument list follows the rules of 'def'; example: (a: int, b: str) -> bool. In this form a "bare" name represents an argument name and has the implicit type Any, like it has in function definitions. (Or Undefined, in checkers that make a distinction, like pyright.)
I would be OK with that too; I don't think mixing the two forms is an important use case.
 

or this?

f: (count: int, str) -> bool

or even this?

f: (a: int, b, c: str) -> bool
These two would be illegal because a positional-only argument cannot follow a positional-or-keyword argument.

Hm, so with my "simpler" rule, those would be untyped arguments (in the first example, the argument name would be confusingly 'str' and the type 'Any'; in the second, we'd have 'b: Any').

But I honestly don't know what users would expect that to mean -- probably if the name is a known type, they'd expect it to be a type, but if it wasn't, they'd expect it to be an argument name -- but that's not a rule we can implement.
That's a good point, and that seems like an additional argument to make this an error.

This confusion can also appear under your proposal though: maybe a user will write (a, b) -> bool expecting a function with two arguments of any type.
 
As a side note, CPython is already able to parse a subset of this syntax, though the feature is undocumented:

>>> ast.dump(compile("(a, b) -> int", "", mode="func_type", flags=ast.PyCF_ONLY_AST))
"FunctionType(argtypes=[Name(id='a', ctx=Load()), Name(id='b', ctx=Load())], returns=Name(id='int', ctx=Load()))"

--
--Guido van Rossum (python.org/~guido)