Sling Academy
Home/Python/Understanding ‘Never’ type in Python 3.11+ (5 examples)

Understanding ‘Never’ type in Python 3.11+ (5 examples)

Last updated: February 22, 2024

Introduction

Python 3.11 introduces a variety of exciting new features and improvements over its predecessors. Among these, the introduction of the ‘Never’ type stands out as a significant addition for type hinting. This tutorial aims to demystify the ‘Never’ type through detailed explanations accompanied by practical examples.

The ‘Never’ type, as its name suggests, indicates that a certain code path should never be expected to return. It can be particularly useful in functions that intentionally do not return a value (not even None) because they raise an exception or enter an infinite loop. This offers more precision in type annotations, improving the assistance provided by type checkers and enhancing code readability.

When to Use the ‘Never’ Type

  1. For functions that always raise an exception: If a function’s sole purpose is to raise an exception and it will never return a value, it should be annotated with ‘Never’.
  2. Infinite loops: Functions designed to never return because they loop infinitely can also be annotated with ‘Never’.
  3. Unreachable code paths: In scenarios where a code path is logically unreachable, using ‘Never’ can make this explicit. This is less common but can be helpful in complex logic.

Examples of ‘Never’ Type Usage

Let’s delve deeper with practical examples to understand how and when to use the ‘Never’ type in Python 3.11+.

Example 1: Raising an Exception

from typing import Never

def raise_error() -> Never:
    raise ValueError('This function always raises an exception')

raise_error()

This function is annotated with ‘Never’ to denote that it will never return normally. It’s a clear indicator to developers and tools that its execution path ends with an exception.

Example 2: Infinite Loops

from typing import Never

def wait_forever() -> Never:
    while True:
        pass

This function uses an infinite loop and is annotated with ‘Never’. It serves as a very clear documentation that the function is intended never to exit under normal execution paths.

Example 3: Unreachable Code

from typing import Never

def example_function(x: int) -> int | Never:
    if x % 2 == 0:
        return x
    else:
        raise Exception('Only even numbers are accepted')

In this example, ‘Never’ is used to indicate that, for some inputs, the function does not return normally. This is somewhat advanced usage, demonstrating ‘Never’ for code that might not always execute.

Example 4: Type Checkers’ Best Friend

from typing import Never

def always_fail() -> Never:
    raise Exception("This function always fails")

Here, the function always_fail explicitly raises an exception to indicate failure. This aligns with the use of Never as the return type, clearly signaling to anyone reading the code that this function is not expected to return normally under any circumstances.

Example 5: Complex Use Cases

from typing import Union, Never

def process_data(data: Union[str, int]) -> int | Never:
    if isinstance(data, str):
        return len(data)
    else:
        log_and_exit('Only strings are allowed')

def log_and_exit(message: str) -> Never:
    print(message)
    raise SystemExit

This example combines several concepts. The log_and_exit function, annotated with ‘Never’, is designed to log an error and then terminate the program. The process_data function can either return an int or, in case of invalid input, never return because it calls log_and_exit.

Conclusion

The introduction of the ‘Never’ type in Python 3.11+ enriches the language’s type hinting capabilities. By accurately marking functions that are not expected to return, developers can write more explicit, self-documenting, and safer code. While it might not be needed in everyday code, understanding ‘Never’ broadens your Python arsenal, enabling more precise typing in complex projects.

If you’re looking to deepen your Python expertise, integrating ‘Never’ into your type hinting practices could be a valuable next step. Remember, the best way to understand and remember new concepts is by applying them. So, consider where ‘Never’ might make your code more robust and self-explanatory, and experiment with it in your next project.

Next Article: Python: Using type hints with class methods and properties

Previous Article: Using TypeGuard in Python (Python 3.10+)

Series: Basic Python Tutorials

Python

You May Also Like

  • Python Warning: Secure coding is not enabled for restorable state
  • Python TypeError: write() argument must be str, not bytes
  • 4 ways to install Python modules on Windows without admin rights
  • Python TypeError: object of type ‘NoneType’ has no len()
  • Python: How to access command-line arguments (3 approaches)
  • Python: 3 Ways to Retrieve City/Country from IP Address
  • Using Type Aliases in Python: A Practical Guide (with Examples)
  • Python: Defining distinct types using NewType class
  • Using Optional Type in Python (explained with examples)
  • Python: How to Override Methods in Classes
  • Python: Define Generic Types for Lists of Nested Dictionaries
  • Python: Defining type for a list that can contain both numbers and strings
  • Using TypeGuard in Python (Python 3.10+)
  • Python: Using ‘NoReturn’ type with functions
  • Type Casting in Python: The Ultimate Guide (with Examples)
  • Python: Using type hints with class methods and properties
  • Python: Typing a function with default parameters
  • Python: Typing a function that can return multiple types
  • Python: Typing a function with *args and **kwargs