What are the drawbacks or benefits to using types.FunctionType vs typing.Callable as a type-hint annotation?
Consider the following code...
import types
import typing
def functionA(func: types.FunctionType):
rt = func()
print(func.__name__)
return rt
def functionB(func: typing.Callable):
rt = func()
print(func.__name__)
return rt
The only difference I can see is Callable could be any sort of callable object (function, method, class, etc) while FunctionType is limited to only functions.
Am I overlooking something? Is there a benefit to using FunctionType over Callable in certain situations?
The types module predates PEP 484 annotations and was created mostly to make runtime introspection of objects easier. For example, to determine if some value is a function, you can run isinstance(my_var, types.FunctionType).
The typing module contains type hints that are specifically intended to assist static analysis tools such as mypy. For example, suppose you want to indicate that a parameter must be a function that accepts two ints and returns a str. You can do so like this:
def handle(f: Callable[[int, int], str]) -> None: ...
There is no way to use FunctionType in a similar manner: it simply was not designed for this purpose.
This function signature is also more flexible: it can also accept things like objects with a __call__ since such objects are indeed callable.
The contents of the typing module can also sometimes be used for runtime checks in a manner similar to the contents of types as a convenience: for example, doing isinstance(f, Callable) works. However, this functionality is deliberately limited: doing isinstance(f, Callable[[int, int], str]) is intentionally disallowed. Attempting to perform that check will raise an exception at runtime.
That said, I don't think it's a good style to perform runtime checks using anything from typing: the typing module is meant first and foremost for static analysis.
I would not use anything from the types module within type hints for similar reasons. The only exception is if your function is written in a way such that it's critical that the value you need to receive is specifically an instance of FunctionType, rather than being any arbitrary callable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With