6

If a function can return None, shouldn't the type annotation use NoneType?

For example, shouldn't we use this:

from types import NoneType

def my_function(num: int) -> int | NoneType:

    if num > 0:
        return num

    return None

instead of:

def my_function(num: int) -> int | None:

    if num > 0:
        return num

    return None

?

BrokenBenchmark
  • 18,126
  • 7
  • 21
  • 33
Brian
  • 388
  • 3
  • 8

1 Answers1

9

No. types.NoneType was removed in Python 3. Attempting to import NoneType from types will produce an ImportError in Python 3, before Python 3.10. (For Python 3.10, types.NoneType was reintroduced; however, for the purposes of type hinting, types.NoneType and None are equivalent, and you should prefer the latter for conciseness.)

In Python 3.10, int | None is the way to describe a return type that could possibly be None. However, for Python versions earlier than 3.10, this syntax is unsupported, so you should use Optional[int] instead.

BrokenBenchmark
  • 18,126
  • 7
  • 21
  • 33
  • What about this? https://github.com/python/cpython/blob/3.10/Lib/types.py#L304 – Brian Feb 15 '22 at 06:40
  • Also I saw this, https://www.python.org/dev/peps/pep-0484/#using-none does it mean both are fine? And if both are fine which one should I prefer? – Brian Feb 15 '22 at 06:43
  • [This PEP](https://www.python.org/dev/peps/pep-0604/) uses `None` over `NoneType`, and the [`mypy` documentation](https://mypy.readthedocs.io/en/stable/kinds_of_types.html#optional-types-and-the-none-type) suggests using `None` (although this is in a section that may not have been updated with respect to Python 3.10). Regardless, I would suggest using `None` as it's more concise. – BrokenBenchmark Feb 15 '22 at 06:46
  • At the very least, trying to import `NoneType` produces an import error on Python 3.8. – BrokenBenchmark Feb 15 '22 at 06:47
  • 1
    Ok, thank you for confirming. I will use `None` in the future. – Brian Feb 15 '22 at 06:48
  • I've actually found something interesting in the documentation. Here https://docs.python.org/3/library/types.html#types.NoneType, it says `NoneType` is new in Python 3.10. I think they may have added it back? When I import NoneType, it does not cause an error, but I am using Python 3.10. It is also mentioned in the release notes: https://docs.python.org/3/whatsnew/3.10.html#types. – Brian Feb 15 '22 at 06:58
  • 1
    Yeah, looks like it's new to Python 3.10. [This discussion](https://bugs.python.org/issue41810) describes the decision to add it into Python 3.10 for consistency reasons (to support ellipsis in static typechecking). – BrokenBenchmark Feb 15 '22 at 07:00
  • Functionally, there is no difference -- [`None` is replaced by `type(None)` for type hinting purposes](https://docs.python.org/3/library/typing.html#type-aliases). So, I'd still suggest using `None` over `NoneType`. – BrokenBenchmark Feb 15 '22 at 07:04