525

How can I specify the type hint of a variable as a function type? There is no typing.Function, and I could not find anything in the relevant PEP, PEP 483.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Jon
  • 11,356
  • 5
  • 40
  • 74
  • 73
    A function is [`Callable`](https://www.python.org/dev/peps/pep-0483/#fundamental-building-blocks) – jonrsharpe Jun 15 '16 at 12:17
  • 5
    https://www.python.org/dev/peps/pep-0483/#fundamental-building-blocks, last bullet point before "we might add". –  Jun 15 '16 at 12:18

4 Answers4

745

As @jonrsharpe noted in a comment, this can be done with typing.Callable:

from typing 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]
Federico Baù
  • 6,013
  • 5
  • 30
  • 38
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
  • 3
    @javadba - oh, yes, but I'm still not sure on which dial... By the way - what about `Callable[[Arg, Types, Here], ...]` for `*args`, `**kwargs`, keyword-only args and positional only args? Have they not thought about calling convention in the type signatures for callables? ;) – Tomasz Gandor May 28 '20 at 21:05
  • 2
    [According to the docs](https://docs.python.org/3/library/typing.html#typing.Callable), `typing.Callable` seems to be in favor of `collections.abc.Callable`: – Nick Crews Feb 20 '21 at 00:03
  • more info at https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html – the1gofer Apr 08 '22 at 15:40
  • 1
    Note that this is not quite the same thing. A function is a Callable but the programmer might be interested in specific attributes of functions, such as their unique dunder methods. – Christopher Barber Jul 21 '22 at 13:17
  • since all methods take `self` as a parameter, is the answer any different for methods? – Harvs Sep 26 '22 at 12:22
  • nit: the parameters aren't subscripted, that's just a list literal... – somebody Nov 13 '22 at 13:00
  • Is it possible to give variable names along with datatypes in type hints? – Avneesh Mishra Nov 26 '22 at 11:38
20

Another interesting point to note is that you can use the built in function type() to get the type of a built in function and use that. So you could have

def f(my_function: type(abs)) -> int:
    return my_function(100)

Or something of that form

Hallsville3
  • 487
  • 3
  • 7
  • 3
    A type hint can be whatever you wish, but they haven't always been lazy evaluated. Also, does your function really only take `builtin_function_or_method` as `my_function`? Wouldn't a `lambda` work? A user defined function or bound method? – Tomasz Gandor May 28 '20 at 21:10
  • 9
    No you cannot, when running `mypy`, this gives the error: `error: Invalid type comment or annotation` `note: Suggestion: use type[...] instead of type(...)`. – ruohola Feb 28 '21 at 13:52
  • 1
    note that `type(abs)` is just `builtin_function_or_method`... which i doubt very many things understand (ignoring the fact that it doesn't specify args, and ignoring the fact it's not even correct for this case) – somebody Nov 13 '22 at 13:23
14

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.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
John Carrell
  • 1,662
  • 3
  • 21
  • 31
13

In python3 it works without import typing:

def my_function(other_function: callable):
    pass
Jack Scandall
  • 338
  • 3
  • 6
  • 3
    https://docs.python.org/3/library/typing.html#callable typing.Callable is NOT deprecated – Vladimir Aug 19 '22 at 06:36
  • 12
    this is actually a bit misleading because lowercase callable is actually a built-in function, not a class (or protocol) itself. If you want to allow any class that implements the __call__ method, use Callable from the typing module. If you want to be more specific and allow only functions, use FunctionType from types module. – Nicolas Fonteyne Nov 23 '22 at 19:51
  • 2
    This also raises a TypeError when used as part of a union type: `def my_function(other_function: callable | None):`, at least on Python 3.10 – mcsoini Apr 21 '23 at 09:41