
Python 类型注解进阶没效果多半是 mypy 严格模式没配对老哥们是不是经常在项目里加了类型注解结果 mypy 跑起来一片绿上线还是报 AttributeError九成原因是默认配置太水。mypy 默认为了兼容性对很多类型错误睁一只眼闭一只眼。今天不聊基础语法直接上生产级的 mypy.ini 严格配置把类型检查变成真正的 CI 门禁。先甩出一个推荐的 mypy.ini 核心配置别直接 copy理解每项含义再上生产[mypy] disallow_untyped_defs True disallow_any_generics True strict_optional True warn_return_any True坑一函数不写注解也能过默认情况下mypy 允许混合使用类型注解。老代码没注解新代码有注解它能忍。但这会导致类型推断链断裂因为 mypy 基于结构子类型原理一旦上游是 Any下游全变 Any。# demo1.py def add(a, b): # 没有类型注解 return a b def process(x: int) - int: return add(x, 10) # mypy 默认可能不报错 print(process(5))**效果** 默认配置下 mypy 可能仅警告或不报错。开启 disallow_untyped_defs True 后直接报 error: Function is missing a type annotation。这能强制团队补全核心逻辑的类型定义防止推断失效确保类型流贯穿整个调用链避免隐式 Any 污染。坑二泛型偷懒写 List 而不是 List[int]很多人喜欢用 List 不带参数或者 Dict 不带泛型。这在严格模式下是绝对禁止的因为等同于 Any失去了检查意义。Python 运行时泛型会擦除但静态检查必须明确否则无法验证容器内容。# demo2.py from typing import List def get_ids() - List: # 缺少泛型参数 return [1, 2, 3] def sum_ids(ids: List) - int: # 这里也是 return sum(ids)**效果** 配置 disallow_any_generics True 后mypy 会报 error: Missing type parameters for generic type List。这逼着你明确数据结构内容避免把字符串列表传给期望整数的函数从源头杜绝类型混淆减少运行时类型转换错误。坑三None 值处理不当引发崩溃生产环境最多的崩溃就是 NoneType has no attribute。默认 mypy 不强制检查 Optional 类型导致很多潜在的空指针风险被忽略。这是动态语言转静态检查最痛的一点必须显式声明可能为空。# demo3.py def get_user(uid: int) - dict: # 实际可能返回 None if uid 0: return None return {id: uid} user get_user(0) print(user[id]) # 运行时崩溃**效果** 开启 strict_optional True 并修正返回类型为 Optional[dict]mypy 会在使用 user[id] 前报错 error: Value of type None is not indexable。强迫你在代码里先做 if user is not None 判断将运行时异常提前到编码阶段发现大幅降低线上空指针概率。生产环境避坑清单1. **不要直接上 --strict**先开 disallow_untyped_defs再逐步加 disallow_any_generics最后上 strict_optional。2. **遗留代码豁免**用 [mypy-old_module.*] 单独配置宽松策略别阻碍重构新代码必须严格。3. **插件兼容**用了 pydantic 或 sqlalchemy 记得装对应 mypy 插件否则报假错影响开发效率。4. **CI 集成**将 mypy 检查放入 GitLab CI 或 GitHub Actions合并请求前必须通过否则禁止合入。类型注解不是写给自己看的是给工具和后人看的。配置不到位注解就是装饰器。你们团队 mypy 是强制 CI 通过还是仅做提示