289

In python 3.x, it is common to use return type annotation of a function, such as:

def foo() -> str:
    return "bar"

What is the correct annotation for the "void" type?

I'm considering 3 options:

  1. def foo() -> None:
    • not logical IMO, because None is not a type,
  2. def foo() -> type(None):
    • using the best syntax I know for obtaining NoneType,
  3. def foo():
    • omit explicit return type information.

Option 2. seems the most logical to me, but I've already seen some instances of 1.

5
  • 49
    FWIW, Python doesn't have functions with void return type. Any function (or branch in a function) without an explicit return will return None. I assume the OP understands that, this comment is mostly for the benefit of future readers...
    – PM 2Ring
    Commented Apr 22, 2016 at 15:47
  • Well, this question is not as popular as "why does my function return None in Python?" (I made this question up), so probably most readers already know the default behavior. The dilemma 1 vs 2 is solved in the answer. But what about 3? For "procedures" I actually would prefer option 3, without useless clutter (after all, this function doesn't return anything). Commented May 30, 2018 at 7:41
  • @TomaszGandor Agree. When a function or a method contains no return statement it is needless to specify its return type.
    – Jeyekomon
    Commented Jun 12, 2019 at 13:42
  • It is true that just using None for type hinting seems not logical because it is not a type, unless one knows that internally None is interpreted as type(None), which is NoneType. Commented Mar 30, 2022 at 0:17
  • Option 3 has the disadvantage of skipping mypy validation for the entire function body, when using mypy default settings.
    – Gogowitsch
    Commented Apr 23 at 14:49

2 Answers 2

317

Use option 1 for simplicity & adherence to spec.

def foo() -> None

Option 1 & 2 are the 'same' as per PEP 484 -- Type Hints, ...

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

but the type-hinting specification does not use type(...).

This is why most of the examples use None as return type.

5
  • 55
    To clarify, choose option 1 above. Commented Nov 1, 2016 at 18:58
  • 14
    What about the NoReturn type python.org/dev/peps/pep-0484/#the-noreturn-type ?
    – asmaier
    Commented Nov 22, 2017 at 11:09
  • 28
    @asmaier according to this question which cites PEP 484 — Type Hints NoReturn type is used "...to annotate functions that never return normally. For example, a function that unconditionally raises an exception..." Commented Feb 27, 2018 at 14:54
  • To add to this point -- there is a class NoneType which is NOT the same as None. (None != type(None)). If you are inspecting the return type of say a function with -> None typing hint. You want to be checking if typing.get_type_hints(func)['return'] == type(None)
    – malanb5
    Commented May 30, 2021 at 18:44
  • Also FWIW, VS Code likes 1, not 2. I'm just getting comfy with VS Code, so don't confuse me with an expert.
    – RadlyEel
    Commented Dec 12, 2022 at 19:21
147

TLDR: The idiomatic equivalent of a void return type annotation is -> None.

def foo() -> None:
    ...

This matches that a function without return or just a bare return evaluates to None.

def void_func():  # unannotated void function
    pass

print(void_func())  # None

Omitting the return type does not mean that there is no return value. As per PEP 484:

For a checked function, the default annotation for arguments and for the return type is Any.

This means the value is considered dynamically typed and statically supports any operation. That is practically the opposite meaning of void.


Type-hinting in Python does not strictly require actual types. For example, annotations may use strings of type names: Union[str, int], Union[str, 'int'], 'Union[str, int]' and various variants are equivalent.

Similarly, the type annotation None is considered to mean "is of NoneType". This can be used in other situations as well as return types, though you will see it most often as a return-type annotation:

bar : None

def foo(baz: None) -> None:
    return None

This also applies to generic types. For example, you can use None in Generator[int, None, None] to indicate a generator does not take or return values.


Even though PEP 484 suggests that None means type(None), you should not use the latter form explicitly. The type-hinting specification does not include any form of type(...). This is technically a runtime expression, and its support is entirely up to the type checker. The mypy project is considering whether to remove support for type(None) and remove it from 484 as well.

Or maybe we should update PEP 484 to not suggest that type(None) is valid as a type, and None is the only correct spelling? There should one -- and preferably only one -- obvious way to do it etc.

--- JukkaL, 18 May 2018

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.