11

I want to use type hinting for a function with no parameters

from typing import Callable

def no_parameters_returns_int() -> int:
    return 7

def get_int_returns_int(a: int) -> int:
    return a
    
def call_function(next_method: Callable[[], int]):
    print(next_method())

call_function(no_parameters_returns_int)  # no indication of error from IDE expected
call_function(get_int_returns_int)        # expected an indication of error from IDE

I expected PyCharm to mark the line when I pass a function that does take parameters. Also tried Callabale[[None], int] and Callabale[[...], int]. However the first one hinting the passed function to receive a None type argument, second one hinting the passed function to receive at least one argument.

Is it possible to hint that the passed function receives no arguments?

bad_coder
  • 11,289
  • 20
  • 44
  • 72
Eliy Arlev
  • 511
  • 1
  • 4
  • 14
  • 1
    MyPy detects it correctly: https://mypy-play.net/?mypy=latest&python=3.8&gist=fdaee2f85e8d21575885b86a7a63600b – jonrsharpe Oct 10 '20 at 21:17
  • @jonrsharpe thanks, I switched to Callable[..., int] and got no errors from hinting, however I expected an error at runtime – Eliy Arlev Oct 10 '20 at 21:28
  • What do you mean at runtime? Python doesn't type check at runtime, I assumed you were asking about PyCharm's failure to warn. – jonrsharpe Oct 10 '20 at 21:29
  • @jonrsharpe I meant that when python interpreter executes the line hof(one_arg) it should result in an error. However I opened your code on mypy and changed Callable[[], int] to Callable[..., int] and now there are no errors. Does mypy-play just tests type checking? – Eliy Arlev Oct 10 '20 at 21:37

1 Answers1

6

Is it possible to hint that the passed function receives no arguments?

The correct way to type hint a Callable without arguments is stated in:

"Fundamental building blocks", PEP 483

Callable[[t1, t2, ..., tn], tr]. A function with positional argument types t1 etc., and return type tr. The argument list may be empty n==0.

An explicit example is given in:

"Covariance and Contravariance", PEP 483

- Callable[[], int] is a subtype of Callable[[], float].
- Callable[[], Manager] is a subtype of Callable[[], Employee].

And also in:

"Callable", PEP 484

from typing import Callable

def feeder(get_next_item: Callable[[], str]) -> None:
   # Body

The built-in name None should be distinguished from the type None (the first is used to access the second):

3.2. The standard type hierarchy, Data Model

None

  • This type has a single value. There is a single object with this value. This object is accessed through the built-in name None.

The syntax and meaning of the built-in name None used as a type hint is a special case:

"Using None", PEP 484

When used in a type hint, the expression None is considered equivalent to type(None).

Considering the above, it's less of a surprise the following two ways -of trying to write a Callable type hint of a function without arguments- are wrong:

Callable[[None], tr]
Callable[[type(None)], tr]

The Ellipsis in a Callable type hint simply means:

"Callable", PEP 484

Note that there are no square brackets around the ellipsis. The arguments of the callback are completely unconstrained in this case (and keyword arguments are acceptable).

Since it is "unconstrained" the following is unlikely to cause the static type checker to issue any warnings because of arguments:

Callable[..., tr]

Worth noting, the relation between Callable, Any and ... (Ellipsis).

"The Any type", PEP 484

As well, a bare Callable in an annotation is equivalent to Callable[..., Any]



Finally, if you run your code through MyPy the expected warning is in fact issued:

main.py:13: error: Argument 1 to "call_function" has incompatible type "Callable[[int], int]"; expected "Callable[[], int]" Found 1 error in 1 file (checked 1 source file)

I checked your example in PyCharm 2020.2 Pro and the IDE does not issue the above warning. Notice that PyCharm uses its own implementation of PEP 484, and their static type checker has been know to have bugs.

I think you found a bug...

bad_coder
  • 11,289
  • 20
  • 44
  • 72