I have a function which should receive another function as an argument, I defined that parameter annotation as:
input_function: Callable[
[
Optional[InputType],
Optional[Sequence[str]],
Optional[bool]
],
Awaitable[str]
] = func
And also, my func
function:
async def func(input_type: InputType = None, formats: Sequence[str] = (), *, hide: bool = False) -> str: ...
The function signature and parameter annotation should be the same. However, when I call that function with only one parameter (as all of the parameters are optional) PyCharm says that there are unfilled parameters:
CodePudding user response:
TLDR: Define the signature as a Protocol
with __call__
, not a Callable
.
from typing import Protocol
class InputFunction(Protocol):
async def __call__(self, input_type: InputType = None, formats: Sequence[str] = (), *, hide: bool = False) -> str: ...
input_function: InputFunction = func
The Callable
type can only express a limited kind of signatures: Explicit positional parameters such as Callable[[A, B], R]
or arbitrary parameters such as Callable[..., R]
. Typing one of its parameter as Optional[T]
means it must be "a T
or None
", not that it can be omitted.
In contrast, a Protocol
's __call__
method allows to define the signature using regular definition syntax, including all of its features such as default values.
Callback Protocols
Protocols can be used to define flexible callback types that are hard (or even impossible) to express using the
Callable[...]
syntax, such as variadic, overloaded, and complex generic callbacks. They are defined with a special__call__
member:
While a Protocol
is a class, it matches structurally: defining it with just a __call__
method merely encodes "callable object of same signature", and functions of same signature satisfy this as well.
Note that the self
parameter is required on the __call__
definition, but not used to check whether signatures match.
CodePudding user response:
The documentation for typing.Optional states:
Note that this is not the same concept as an optional argument, which is one that has a default.
And the documentation for typing.Callable states:
There is no syntax to indicate optional or keyword arguments
As such, it is not possible to accurately define the type of the function the way you want it.