Search code examples
pythonpython-3.xconstantsimmutabilitypython-typing

How to make a list (or any other value) immutable: a real constant in Python?


In an old discussion I found the reference to typing Final. I tried the example from the docs:

y: Final[Sequence[str]] = ['a', 'b']
y.append('x')  # Error: "Sequence[str]" has no attribute "append"
z: Final = ('a', 'b')  # Also works

But opposing to the docs it mutates y to ['a','b','x'] without error. I'm on Python 3.11. What's going on? And moreover: What's the state of the art creating immutable constants in 2024 in Python?

Currently I use @dataclass(frozen=True) to accomplish immuability, but there might be more straight forward solutions.

The old discussions do not help with modern features of Python 3.10+.


Solution

  • Type checkers can only hint you ("statically") that you are doing something wrong here. In runtime, Python interpreter doesn't care about what type hints say. (Unless you're using libraries like Pydantic for example which enforces this but it's out of scope here)

    Lets talk about Final. From documentation:

    The typing.Final type qualifier is used to indicate that a variable or attribute should not be reassigned, redefined, or overridden

    It is talking about assignment for the label y! not mutating the object that y points to. .append() "mutates" the object. You still have your y pointing to the same list. So it doesn't prevent you. And that's why you don't see any error regarding this. That error comes from Sequence. If you want to mutate a sequence you should use MutableSequence.

    You can use tuple instead of a mutable list (although they have other differences too) or create your own list-like class: https://stackoverflow.com/a/22340603/13944524