blob: 297b97eca787331563218245d13feba748f86763 [file] [log] [blame]
.. _final_attrs:
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:
.. code-block:: python
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:
.. code-block:: python
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 :py:class:`@property <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:
.. code-block:: python
ID: Final[int] = 1
Here mypy will infer type ``int`` for ``ID``.
* You can omit the type:
.. code-block:: python
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
:py:meth:`__init__ <object.__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 :py:meth:`__init__ <object.__init__>` method (you can skip the
initializer in stub files):
.. code-block:: python
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:
.. code-block:: python
x: list[Final[int]] = [] # Error!
def fun(x: Final[list[int]]) -> None: # Error!
...
``Final`` and :py:data:`~typing.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 :py:meth:`__init__ <object.__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:
.. code-block:: python
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:
.. code-block:: python
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:
.. code-block:: python
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):
.. code-block:: python
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:
.. code-block:: python
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.
.. code-block:: python
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