Reputation: 700
I am trying to properly type hint my code and encountered both Callable and FunctionType
from typing import Callable
def my_func() -> Callable:
f = lambda: _
return f
result = my_func()
type(result) # <class 'function'>
isinstance(result, Callable) # True
vs
from types import FunctionType
def my_func() -> FunctionType
f = lambda: ...
return f
result = my_func()
type(result) # <class 'function'>
isinstance(result, FunctionType) # True
One possible case I can think of is to distinguish between regular and class-based callables like this
class C:
def __call__(self):
pass
def my_func() -> Callable:
c = C()
return c
result = my_func()
type(result) # <class 'function'>
isinstance(result, Callable) # True
isinstance(result, FunctionType) # False
What are the differences between those and when I have to use one over the other?
Upvotes: 0
Views: 895
Reputation: 5284
types.FunctionType
is dynamically defined in cpython/Lib/types.py#L11-L12 as the type of the simplest function.
def _f(): pass
FunctionType = type(_f)
typing.Callable
on the other hand is defined as a wrapped collections.abc.Callable
which a) should be used directly if using python >= 3.9 and b) is itself defined in cpython/Lib/_collections_abc.py#L534-L548 as something having a __call__
method.
class Callable(metaclass=ABCMeta): # NOTE: I'm skipping most of the definition
@classmethod
def __subclasshook__(cls, C):
if cls is Callable:
return _check_methods(C, "__call__")
return NotImplemented
You have highlighted correctly that nearly anything can be a callable, just need to give it a __call__
method, on the other hand, a class will never be a function.
You should use Callable
in most cases unless you are completely certain you need a function only.
Moreover, you can (and should) type the arguments and return value of Callable
, for instance:
Callable[[], None]
-- no arg, returns None
(e.g. lambda: None
)Callable[[int, int], int]
-- two int
args, returns an int
Callable[..., None]
-- any arg, returns None
, (e.g. print
).Upvotes: 1