Description
Right now you can specify callables with two patterns of arguments (shown here by example):
Callable[..., int]
takes in any arguments, any number.Callable[[int, str, bool], int]
takes in a predetermined number of required positional arguments, none of which have names specified.
These don't cleanly match the actual types of callable objects in Python. Argument names, whether arguments are optional, and whether arguments are *args
or **kwargs
do affect the type of a callable. We should be able to spell these things in the type language. Doing so would enable us to correctly write the types of callback functions, for example.
Callable should take two arguments: an argument list and a return type. The return type is exactly as currently described in PEP484. The argument list is either:
...
, indicating the function can take any arguments at all.- Square brackets around a comma separated series of argument specifiers (argspec for short), indicating particulars about the functions arguments
An argument specifier is one of:
- A bare type
TYP
. This has the same meaning asArg(TYP)
Arg(type, name=None)
, indicating a positional argument. If the name is specified, the argument must have that name.OptionalArg(type, name=None)
, indicating an optional positional argument. If the name is specified, the argument must have that name. (alternate name possibilityOptArg(type, name=None)
StarArg(type)
, indicating a "star argument" like*args
KwArg(type)
, indicating a "double star argument" like**kwargs
. (an alternate name here would beStar2Arg(type)
.
The round parens are an indication that these are not actual types but rather this new argument specifier thing.
Like the rules for python function arguments, all positional argspecs must come before all optional argspecs must come before zero or one star argspecs must come before zero or one kw argspecs.
This should be able to spell all function types you can make in python by defining single functions or methods, with the exception of functions that need SelfType
to be properly specified, which is an orthogonal concern.
Some statements I think are true:
Callable[[Arg(T1, name='foo'), Arg(T2, name='bar')], R]
is a subtype ofCallable[[T1, T2], R]
Callable[[T1, OptionalArg(T2)], R]
is a subtype ofCallable[[T1], R]
Callable[[StarArg(T1)], R]
is a subtype ofCallable[[], R]
and is also a subtype ofCallable[[T1], R]
and is also a subtype ofCallable[[T1, T1], R]
and so on.Callable[[T1, StarArg(T1)], R]
is a subtype ofCallable[[T1], R]
and is also a subtype ofCallable[[T1, T1], R]
and so on, but is not a subtype ofCallable[[], R]
- If we want to be able to spell overloaded function types we'll need a specific way of combining callable types in the specific way overloading works; this proposal doesn't address that.