{
"$type": "site.standard.document",
"canonicalUrl": "https://rednafi.com/python/why-noreturn-type-exists/",
"description": "Use Python's NoReturn type to annotate functions that never return normally, helping type checkers understand exception-raising and infinite loop code.",
"path": "/python/why-noreturn-type-exists/",
"publishedAt": "2022-02-21T00:00:00.000Z",
"site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
"tags": [
"Python",
"Typing"
],
"textContent": "Technically, the type of None in Python is NoneType. However, you'll rarely see\ntypes.NoneType being used in the wild as the community has pretty much adopted None to\ndenote the type of the None singleton. This usage is also [documented in PEP-484].\n\nWhenever a callable doesn't return anything, you usually annotate it as follows:\n\nBut sometimes a callable raises an exception and never gets the chance to return anything.\nConsider this example:\n\nThis semantically makes sense and if you run Mypy against the snippet, it won't complain.\nHowever, there's one difference between a callable that returns an implicit None vs one\nthat raises an exception. In the latter case, if you run any code after calling the\ncallable, that code won't be reachable. But Mypy doesn't statically catch that or warn you\nabout the potential dead code. This is apparently fine by the type checker:\n\nNoReturn type can be used in cases like this to warn us about potential dead code ahead.\nTo utilize it, you'd type the above snippet like this:\n\nNotice, that I changed the return type of the raise_verbose_type_error function to\ntyping.NoReturn. Now, if you run Mypy against the snippet with the --warn-unreachable\nflag, it'll complain:\n\nMore practical examples\n\nCallables containing infinite loops\n\nMypy will warn us about the dead code.\n\nAnother case where NoReturn can be useful, is to type callables with while True loops.\nThis is common in webservers:\n\nCallables that invoke 'sys.exit()', 'os.\\_exit()', 'os.execvp()', etc\n\nBoth sys.exit() and os._exit() do similar things. The former function raises the\nSystemExit() exception and exits the program without printing any stacktrace or\nwhatsoever. On the other hand, the latter function exits the process immediately without\nletting the interpreter run any cleanup code. Prefer sys.exit() over os._exit().\n\nThe os.execvp() function execute a new program, replacing the current process. It never\nreturns. Here's how you'd type the callables that call these functions:\n\nFurther reading\n\n- [NoReturn vs None - Anthony explains]\n- [What's the point of NoReturn? - Adam Johnson]\n\n\n\n\n[documented in PEP-484]:\n https://www.python.org/dev/peps/pep-0484/#using-none\n\n[noreturn vs none - anthony explains]:\n https://www.youtube.com/watch?v=-zH0qqDtd4w\n\n[what's the point of noreturn? - adam johnson]:\n https://adamj.eu/tech/2021/05/20/python-type-hints-whats-the-point-of-noreturn/",
"title": "Why 'NoReturn' type exists in Python"
}