You can use the typing module for Callable annotations.
The Callable annotation is supplied a list of argument types and a return type:
from typing import Callable
def func_b(func: Callable[[int], int]) -> int:
return func(3)
Answer from Alex on Stack OverflowYou can use the typing module for Callable annotations.
The Callable annotation is supplied a list of argument types and a return type:
from typing import Callable
def func_b(func: Callable[[int], int]) -> int:
return func(3)
Shouldn't it just be function?
>>> type(func_a)
function
Type annotation for argument that is a function
python - How can I specify the function type in my type hints? - Stack Overflow
What is the point of type hinting when Python doesn't even respect it!?
Do you use static type hints in your code?
Videos
I built a wrapper for an internal backups tools in my company so I can save my team the hassle of setting everything up.
Recently I found out that the tool didn't play well with some characters in the filename of a legacy system that I am not allowed to modify.
I figured I would allow the user to optionally pass in a function that manipulates the basename of file in whichever way they wanted, as long as that function returned a string. I want the function to be called
function(base_key, *function_args)
But mypy seems to dislike this, giving me the error:
Error: List or tuple expected as variable arguments
How should I annotate this code?
I am having trouble googling my problem, I get useless results about stuff before the typing module, or stuff about how to annotate functions, not how to annotate arguments that are functions. Help please?
Full method code:
def backup(self, file_list: List[str], prefix: str = '', sufix: str = '',
function: Optional[Callable[..., str]] = None,
function_args: Optional[List[Any]] = []) -> None:
self.sufix = sufix
self.prefix = prefix
for filename in file_list:
base_key = os.path.basename(filename)
if function:
base_key = function(base_key, *function_args)
key = self.prefix + base_key + self.sufix
self.upload(filename, self.storage_unit, key)As @jonrsharpe noted in a comment, this can be done with collections.abc.Callable:
from collections.abc import Callable
def my_function(func: Callable):
Note: Callable on its own is equivalent to Callable[..., Any].
Such a Callable takes any number and type of arguments (...) and returns a value of any type (Any). If this is too unconstrained, one may also specify the types of the input argument list and return type.
For example, given:
def sum(a: int, b: int) -> int: return a+b
The corresponding annotation is:
Callable[[int, int], int]
That is, the parameters are sub-scripted in the outer subscription with the return type as the second element in the outer subscription. In general:
Callable[[ParamType1, ParamType2, ..., ParamTypeN], ReturnType]
My specific use case for wanting this functionality was to enable rich code completion in PyCharm. Using Callable didn't cause PyCharm to suggest that the object had a .__code__ attribute, which is what I wanted, in this case.
I stumbled across the types module and...
from types import FunctionType
allowed me to annotate an object with FunctionType and, voilà, PyCharm now suggests my object has a .__code__ attribute.
The OP wasn't clear on why this type hint was useful to them. Callable certainly works for anything that implements .__call__() but for further interface clarification, I submit the types module.
Bummer that Python needed two very similar modules.
So infuriating because I feel like my function is lying to me when it ends up letting other objects through the parameter.
Now every function I created needs an instance check which is unintuitive, verbose, and easily forgotten.
def wtf(string: str, integer:int): return 'TYPE HINT DOESNT DO ANYTHING' print( wtf( 123, 'wtf') ) >> 'TYPE HINT DOESNT DO ANYTHING'
EDIT:
Turns out it is a noob mistake. Type hint only functions as a signal for IDE, but developers get to do whatever they want to your parameter.
If you really must enforce it, you got to have the line
if not isinstance(string, str): raise TypeError()
Still, I don't like that this behavior isn't taught until it happens. So much time wasted on debugging production code when you take for granted your function is accepting only restricted data when it doesn't.