typing.Callable is the type you use to indicate a callable. Most python types that support the () operator are of the type collections.abc.Callable. Examples include functions, classmethods, staticmethods, bound methods and lambdas.
In summary, anything with a __call__ method (which is how () is implemented), is a callable.
PEP 677 attempted to introduce implicit tuple-with-arrow syntax, so that something like Callable[[int, str], list[float]] could be expressed much more intuitively as (int, str) -> list[float]. The PEP was rejected because the benefits of the new syntax were not deemed sufficient given the added maintenance burden and possible room for confusion.
PEP 677 – Callable Type Syntax
python typing signature (typing.Callable) for function with kwargs - Stack Overflow
Subtyping rules for `...` in callable types - Typing - Discussions on Python.org
Proposal: Generalize `Callable` to be able to specify argument names and kinds
Videos
typing.Callable is the type you use to indicate a callable. Most python types that support the () operator are of the type collections.abc.Callable. Examples include functions, classmethods, staticmethods, bound methods and lambdas.
In summary, anything with a __call__ method (which is how () is implemented), is a callable.
PEP 677 attempted to introduce implicit tuple-with-arrow syntax, so that something like Callable[[int, str], list[float]] could be expressed much more intuitively as (int, str) -> list[float]. The PEP was rejected because the benefits of the new syntax were not deemed sufficient given the added maintenance burden and possible room for confusion.
The typing module is used for type hints:
This module provides runtime support for type hints.
What are type hints?
The documentation provides this example:
def greeting(name: str) -> str:
return 'Hello ' + name
In the function
greeting, the argument name is expected to be of typestrand the return typestr. Subtypes are accepted as arguments.
How to use typing.Callable
Assume you want to define a function that takes two integers and performs some kind of operation on them that returns another integer:
def apply_func(a: int, b: int, func) -> int:
return func(a, b)
So the expected type of the func argument in apply_func is "something that can be called (e.g. a function) that takes two integer arguments and returns an integer":
typing.Callable[[int, int], int]
Why bother with type hints in the first place?
Using type hints enables you to perform type checking. If you use an IDE like PyCharm or Visual Studio Code, you'll get visual feedback if you're using unexpected types:

You are probably looking for Callback protocols.
In short, when you want to express a callable with a complex signature, what you'll want to do is to create a custom Protocol that defines a __call__ method with the precise signature you want.
For example, in your case:
from typing import Protocol
# Or, if you want to support Python 3.7 and below, install the typing_extensions
# module via pip and do the below:
from typing_extensions import Protocol
class MyCallable(Protocol):
def __call__(self, a: int, b: float) -> float: ...
def good(a: int, b: float) -> float: ...
def bad(x: int, y: float) -> float: ...
def function_executor(a: int, b: float, fn: MyCallable) -> float:
return fn(a=a, b=b)
function_executor(1, 2.3, good) # Ok!
function_executor(1, 2.3, bad) # Errors
If you try type-checking this program using mypy, you'll get the following (admittedly cryptic) error on the last line:
Argument 3 to "function_executor" has incompatible type "Callable[[int, float], float]"; expected "MyCallable"
(Callback protocols are somewhat new, so hopefully the quality of the error messages will improve over time.)
I found the example with the typing callback a bit complicated. For anyone looking for a simple example of typing a function with kwargs:
from typing import Protocol
class MyCallable(Protocol):
# Define types here, as if __call__ were a function (ignore self).
def __call__(self, a: int, b: int) -> int:
...
# Generic function- types correspond to MyCallable.__call__ args.
def func_add(a: int, b: int) -> int:
return a + b
# Assign the function to a variable called my_function, and add the type.
my_function: MyCallable = func_add
my_function(a=1, b=2) # This is OK.
my_function(a=1, b="x") # This is NOK.