1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
|
.. _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 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 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 final, 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
|