Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# Final names, methods and classes

This section introduces these related features:

1. Final names are variables or attributes that should not be reassigned after initialization. They are useful for declaring constants.

2. Final methods should not be overridden in a subclass.

3. Final classes should not be subclassed.

All of these are only enforced by mypy, and only in annotated code. There is no runtime enforcement by the Python runtime.

Note

The examples in this page import `Final` and `final` from the `typing` module. These types were added to `typing` in Python 3.8, but are also available for use in Python 3.4 - 3.7 via the `typing_extensions` package.

## Final names

You can use the `typing.Final` qualifier to indicate that a name or attribute should not be reassigned, redefined, or overridden. This is often useful for module and class level constants as a way to prevent unintended modification. Mypy will prevent further assignments to final names in type-checked code:

    from typing import Final

    RATE: Final = 3_000

    class Base:
        DEFAULT_ID: Final = 0

    RATE = 300  # Error: can't assign to final attribute
    Base.DEFAULT_ID = 1  # Error: can't override a final attribute

Another use case for final attributes is to protect certain attributes from being overridden in a subclass:

    from typing import Final

    class Window:
        BORDER_WIDTH: Final = 2.5
        ...

    class ListView(Window):
        BORDER_WIDTH = 3  # Error: can't override a final attribute

You can use `@property` to make an attribute read-only, but unlike `Final`, it doesn’t work with module attributes, and it doesn’t prevent overriding in subclasses.

### Syntax variants

You can use `Final` in one of these forms:

- You can provide an explicit type using the syntax `Final[<type>]`. Example:

      ID: Final[int] = 1

  Here mypy will infer type `int` for `ID`.

- You can omit the type:

      ID: Final = 1

  Here mypy will infer type `Literal[1]` for `ID`. Note that unlike for generic classes this is not the same as `Final[Any]`.

- In class bodies and stub files you can omit the right hand side and just write `ID: Final[int]`.

- Finally, you can write `self.id: Final = 1` (also optionally with a type in square brackets). This is allowed only in `__init__` methods, so that the final instance attribute is assigned only once when an instance is created.

### Details of using `Final`

These are the two main rules for defining a final name:

- There can be at most one final declaration per module or class for a given attribute. There can’t be separate class-level and instance-level constants with the same name.

- There must be exactly one assignment to a final name.

A final attribute declared in a class body without an initializer must be initialized in the `__init__` method (you can skip the initializer in stub files):

    class ImmutablePoint:
        x: Final[int]
        y: Final[int]  # Error: final attribute without an initializer

        def __init__(self) -> None:
            self.x = 1  # Good

`Final` can only be used as the outermost type in assignments or variable annotations. Using it in any other position is an error. In particular, `Final` can’t be used in annotations for function arguments:

    x: list[Final[int]] = []  # Error!

    def fun(x: Final[list[int]]) ->  None:  # Error!
        ...

`Final` and `ClassVar` should not be used together. Mypy will infer the scope of a final declaration automatically depending on whether it was initialized in the class body or in `__init__`.

A final attribute can’t be overridden by a subclass (even with another explicit final declaration). Note however that a final attribute can override a read-only property:

    class Base:
        @property
        def ID(self) -> int: ...

    class Derived(Base):
        ID: Final = 1  # OK

Declaring a name as final only guarantees that the name will not be re-bound to another value. It doesn’t make the value immutable. You can use immutable ABCs and containers to prevent mutating such values:

    x: Final = ['a', 'b']
    x.append('c')  # OK

    y: Final[Sequence[str]] = ['a', 'b']
    y.append('x')  # Error: Sequence is immutable
    z: Final = ('a', 'b')  # Also an option

## Final methods

Like with attributes, sometimes it is useful to protect a method from overriding. You can use the `typing.final` decorator for this purpose:

    from typing import final

    class Base:
        @final
        def common_name(self) -> None:
            ...

    class Derived(Base):
        def common_name(self) -> None:  # Error: cannot override a final method
            ...

This `@final` decorator can be used with instance methods, class methods, static methods, and properties.

For overloaded methods you should add `@final` on the implementation to make it final (or on the first overload in stubs):

    from typing import Any, overload

    class Base:
        @overload
        def method(self) -> None: ...
        @overload
        def method(self, arg: int) -> int: ...
        @final
        def method(self, x=None):
            ...

## Final classes

You can apply the `typing.final` decorator to a class to indicate to mypy that it should not be subclassed:

    from typing import final

    @final
    class Leaf:
        ...

    class MyLeaf(Leaf):  # Error: Leaf can't be subclassed
        ...

The decorator acts as a declaration for mypy (and as documentation for humans), but it doesn’t actually prevent subclassing at runtime.

Here are some situations where using a final class may be useful:

- A class wasn’t designed to be subclassed. Perhaps subclassing would not work as expected, or subclassing would be error-prone.

- Subclassing would make code harder to understand or maintain. For example, you may want to prevent unnecessarily tight coupling between base classes and subclasses.

- You want to retain the freedom to arbitrarily change the class implementation in the future, and these changes might break subclasses.

An abstract class that defines at least one abstract method or property and has `@final` decorator will generate an error from mypy, since those attributes could never be implemented.

    from abc import ABCMeta, abstractmethod
    from typing import final

    @final
    class A(metaclass=ABCMeta):  # error: Final class A has abstract attributes "f"
        @abstractmethod
        def f(self, x: int) -> None: pass