Python中如何创建真正不可变常量?Final为何未生效?
问题解答
为什么Final标注后仍能修改对象?
typing.Final仅作用于静态类型检查层面,用来约束变量不能被重新赋值,而非在运行时强制限制对象本身的可变性:
- 你的代码中,
y: Final[Sequence[str]]只是告诉类型检查器(如mypy、pyright):y这个变量不能被重新指向其他对象,但它指向的列表本身是可变的。 - Python解释器在运行时完全忽略
Final标注,所以y.append('x')能正常执行——你修改的是列表对象的内容,而非重新给y赋值。 - 文档里的"Error"是类型检查器给出的静态提示,不是Python运行时的报错。只有用类型检查工具扫描代码才会看到该错误,直接运行脚本不会触发。
2024年Python创建不可变常量的最佳方案
根据需求场景选择对应方案:
1. 基础不可变类型(数值、字符串、元组)
直接用大写命名规范+Final标注即可,这类类型本身不可变,Final用来防止变量被重新赋值:
from typing import Final MAX_RETRIES: Final[int] = 3 DEFAULT_NAME: Final[str] = "admin" ALLOWED_EXTENSIONS: Final[tuple[str, ...]] = ("jpg", "png")
2. 不可变容器
- 不可变字典:用
types.MappingProxyType包装普通字典,运行时无法修改:from types import MappingProxyType immutable_dict = MappingProxyType({"key1": "value1", "key2": "value2"}) immutable_dict["key3"] = "value3" # 运行时报错: TypeError - 不可变序列:优先使用元组(本身不可变),但注意元组内的元素如果是可变对象(如列表),元素内部仍可修改。
3. 自定义不可变对象
@dataclass(frozen=True):你当前使用的方案是最直接的官方原生方案,适合复杂数据结构,无需额外依赖:from dataclasses import dataclass @dataclass(frozen=True) class Config: host: str port: int timeout: int cfg = Config("localhost", 8080, 30) cfg.port = 8000 # 运行时报错: FrozenInstanceError- 第三方库
attrs:如果需要更灵活的配置(如字段验证、类型转换),可以用attrs的@frozen装饰器,功能比原生dataclass更丰富:import attrs @attrs.frozen class User: id: int name: str email: str - 手动实现不可变性:重写
__setattr__和__delattr__方法,但代码繁琐,仅适合特殊场景:class ImmutableObject: def __init__(self, value): self._value = value @property def value(self): return self._value def __setattr__(self, name, value): if name != "_value" or hasattr(self, "_value"): raise TypeError("Cannot modify immutable object") super().__setattr__(name, value) def __delattr__(self, name): raise TypeError("Cannot delete attributes from immutable object")
内容的提问来源于stack exchange,提问作者Fred
相关产品推荐
相关产品推荐

