typing.Final仅用于类型检查,不阻止运行时修改;它标记变量不应被重新赋值,但Python解释器忽略该提示,需配合mypy等工具使用。

typing.Final 不能阻止运行时修改,只对类型检查器起作用
typing.Final 是一个类型提示工具,不是运行时保护机制。它告诉 mypy、pyright 等类型检查器:“这个变量不该被重新赋值”,但 Python 解释器完全不管——FINAL_VAR = 42 之后写 FINAL_VAR = 99 不会报错,只会被类型检查器标红。
常见错误现象:mypy 没报错,但你误以为加了 Final 就安全了;或者反过来,mypy 报了错,但代码照样跑通,让你怀疑类型系统没生效。
- 必须配合类型检查器使用(如运行
mypy your_script.py) - 仅适用于模块级变量、类属性(不支持实例属性)
- 对
dict、list等可变对象,Final只锁定引用,不冻结内容(Final[List[int]]允许.append())
声明模块级常量:用 Final + 字面量或调用表达式
适合配置项、协议版本号、固定字符串等。推荐显式标注类型,避免类型推导歧义。
from typing import Final
<p>API_TIMEOUT: Final[int] = 30
DB_URL: Final[str] = "sqlite:///app.db"
SUPPORTED_FORMATS: Final[frozenset[str]] = frozenset({"json", "yaml"})</p><h1>❌ 错误:Final 不能套在函数调用外(mypy 会忽略)</h1><h1>LOG_LEVEL: Final[str] = os.getenv("LOG_LEVEL", "INFO").upper()</h1><h1>✅ 正确:确保右侧是编译期可确定的纯表达式,或用 cast(慎用)</h1><p>立即学习“Python免费学习笔记(深入)”;
注意:如果值来自环境变量、配置文件或运行时计算,Final 失去意义——类型检查器无法验证其“不变性”,此时应改用文档说明 + 命名约定(如全大写)。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
标记类为不可继承:Final 类本身不提供防继承能力
typing.Final 无法用于类定义来禁止继承。Python 中真正能防止子类化的机制是 __init_subclass__ 或元类,而 typing.Final 对类本身没有语义。
常见误解:写 class Base: Final: 或 class FinalBase(Final): —— 这些语法非法,Final 不是基类也不是装饰器。
- 若想禁止继承,需手动抛出异常:
class SealedClass: def __init_subclass__(cls, **kwargs): raise TypeError(f"{cls.__name__} is not designed to be subclassed") -
typing.Final可用于类中的属性,比如class Config: DEBUG: Final[bool] = True,但这和类能否被继承无关 - 某些静态分析工具(如
pylint)支持# pylint: disable=invalid-name配合命名约定(如FINAL_CLASS),但非标准方案
与 @final 装饰器的区别:这才是防重写/防继承的正解
Python 3.8+ 引入了 typing.final(注意小写 final 函数,不是大写 Final 类型),它才是用来标记方法不可重写、类不可继承的运行时+类型检查双保险机制。
from typing import final <p>@final class Utility: def helper(self) -> str: return "do not override"</p><p>class BadChild(Utility): # mypy 报错:Cannot inherit from final class "Utility" pass</p><p>class Parent: @final def template_method(self) -> None: # mypy 报错:Cannot override final method ...</p><p>class Child(Parent): def template_method(self) -> None: # ❌ 运行时不会拦,但 mypy 会标 ...
@final 和 Final 容易混淆:前者是装饰器,影响类/方法的继承与重写行为;后者是类型注解,只约束赋值。两者目标不同,不能互相替代。
真正容易被忽略的是:即使加了 @final,Python 运行时仍允许继承或重写——它只靠类型检查器提前预警。生产环境若需强约束,必须辅以单元测试断言或运行时 __init_subclass__ 拦截。

















