Callbacks, key functions and handlers are everywhere, and their signatures are easy to get wrong.
Callable[[int, str], bool] describes any callable taking an int and a str positionally and returning a bool. Import it from collections.abc (the typing alias is deprecated). Functions, lambdas, bound methods and objects with __call__ all match if their signature fits.
def retry(fn: Callable[[], T], attempts: int) -> T: ...
def on_event(handler: Callable[[str], None]) -> None: ...Useful forms:
Callable[[], None]: takes nothing, returns nothing useful.Callable[..., int]: any arguments, returnsint(the...gives up on checking arguments).Callable[[str], object]: when you ignore the callback's result,objectaccepts functions returning anything, which is clearer thanNone.
Callable can't express keyword arguments, defaults or overloads. For those, define a callback Protocol with a __call__ method, which you'll meet in the Protocols lesson.
Higher-order functions that preserve the signature of what they wrap (decorators) need ParamSpec, an advanced lesson.
Example
from collections.abc import Callable
def apply_twice(fn: Callable[[int], int], x: int) -> int:
return fn(fn(x))
def notify(handler: Callable[[str], object], msg: str) -> None:
handler(msg) # result ignored, so return type object
def make_multiplier(k: int) -> Callable[[int], int]:
return lambda n: n * k
print(apply_twice(lambda n: n + 3, 1)) # 7
print(apply_twice(make_multiplier(10), 2)) # 200
notify(print, "saved") # saved
notify(len, "ok") # fine: len returns int, object accepts it
# apply_twice(str.upper, 1) -> checker error: incompatible Callable typeRemember
- Callable[[Arg1, Arg2], Return] types callbacks
- Import Callable from collections.abc
- Use object as the return type for callbacks whose result you ignore
Watch out for
- Writing Callable[int, int] instead of Callable[[int], int]; the parameter types must be in a list.