:旧式 `%` 格式化参数类型不匹配检查完全指南)
静态分析代码质量Lint开发工具【免费下载链接】pylintIts not just a linter that annoys you!项目地址https://gitcode.com/gh_mirrors/pyl/pylint点击查看免费下载导读bad-string-format-type消息编号 E1307是 Pylint 中用于检测旧式old-style%字符串格式化参数类型不匹配的检查项。当你写出%d % 1这类格式串要求整数、却传入字符串的代码时它会在编译前更准确地说是在静态分析阶段就为你标出隐患。读完本文你将掌握该检查的触发条件、类型匹配的完整规则、边界情况处理方式以及如何在 Pylint 中启用、关闭或定位它。需要特别说明的是该检查目前仅对旧式%格式化生效——即... % value这种写法详见 details.rststr.format()与 f-string 不在其检查范围内。Pylint 官方以 Issue #6163原记录为 #6085跟踪该检查的适用范围问题。消息定义E1307 从哪来bad-string-format-type在 Pylint 源码中定义于 strings.py由StringFormatChecker检查器name string负责触发。其完整定义如下E1307: ( Argument %r does not match format type %r, bad-string-format-type, Used when a type required by format string is not suitable for actual argument type, ),消息符号symbolbad-string-format-type消息编号msg-idE1307属于 Error 级别报错文案Argument builtins.str does not match format type d触发时机格式串要求的类型与实际传入参数的类型不匹配时在文档体系中该消息被归类为 error 类别参见 messages_overview.rst 与 features.rst 中的条目。触发场景什么代码会被报错最简单的反面示例仓库在 doc/data/messages/b/bad-string-format-type/bad.py 中给出了最小触发样例print(%d % 1) # [bad-string-format-type]%d要求整数decimal却传入了字符串1——尽管运行时的%d % 1在 CPython 中实际上会成功因为旧式格式化会在运行时做隐式转换但从类型正确性的角度这正是 Pylint 想要拦截的隐患隐式依赖运行时转换往往是 bug 与脆弱代码的温床。正面示例同目录下的 good.py 给出正确写法print(%d % 1)更丰富的真实用例仓库的功能测试文件 tests/functional/b/bad_string_format_type.py 提供了覆盖面更广的触发矩阵对应的期望输出记录在 bad_string_format_type.txt 中%d % 1 # [bad-string-format-type] %(key)d % {key: 1} # [bad-string-format-type] %x % 1.1 # [bad-string-format-type] %(key)x % {key: 1.1} # [bad-string-format-type] %d % [] # [bad-string-format-type] %(key)d % {key: []} # [bad-string-format-type] WORD abc %d % WORD # [bad-string-format-type] %d %s % (WORD, WORD) # [bad-string-format-type] VALUES_TO_FORMAT (1, 2, 3.0) %d %s %f % VALUES_TO_FORMAT # 通过1 是 int、2 是 str、3.0 是 float %d %d %f % VALUES_TO_FORMAT # [bad-string-format-type]第 2 个 %d 遇到 2可以看到位置参数与映射字典参数两种形式都会被检查既有%d % x也有%(key)d % {key: x}这类带命名键的写法常量、变量、元组展开都能被推断WORD是字符串常量VALUES_TO_FORMAT是元组Pylint 均能逐个元素推断出类型并完成逐槽位比对当值来自函数参数、无法静态推断时Pylint 保持沉默测试文件中的test_format函数传入my_input_value等参数此时无法确定内容Pylint 不报错也不崩溃源码中表现为num_args None时跳过检查。类型匹配规则arg_matches_format_type源码解析该检查的核心判定逻辑集中在 strings.py 的arg_matches_format_type函数中理解它就能准确预判 Pylint 的报错行为def arg_matches_format_type( arg_type: SuccessfulInferenceResult, format_type: str ) - bool: if format_type in sra: # All types can be printed with %s, %r and %a return True if isinstance(arg_type, astroid.Instance): # Subclasses behave like their builtin base: bool and IntEnum # members format like int, a float subclass like float. if arg_type.is_subtype_of(builtins.str): return format_type c if arg_type.is_subtype_of(builtins.int): # Integers allow all types return True if arg_type.is_subtype_of(builtins.float): # i and u accept a float at runtime (truncated like d) return format_type in diueEfFgGn% return False return True逐条解读这条判定表场景判定说明格式类型为%s、%r、%a总是匹配字符串化、repr、ascii 三种格式接受任意类型参数是str的子类仅当格式类型为%c时匹配%c单字符接受单字符字符串但字符串不能用于%d、%x等数值格式参数是int的子类总是匹配整数可被所有格式接受bool、IntEnum成员都按int处理参数是float的子类格式类型须属于diueEfFgGn%%i/%u在运行时会把 float 截断成 int行为类似%d因此也算合法其他未知/无法推断的类型总是匹配放行非astroid.Instance或无法推断时不做误报这条规则的两个关键推论%s/%r/%a是万能格式%s % []、%s % None都不会被报错测试文件 19–22 行验证了这一点%d遇到字符串、%x遇到浮点数会被报错因为它们之间存在真实的类型语义偏差。触发流程从%运算到消息上报从 strings.py 的visit_binop方法可以看到完整的调用链入口StringFormatChecker.visit_binop只处理运算符为%的二元运算if node.op ! %: return并要求左操作数是字符串常量解析格式串调用utils.parse_format_string(format_string)解析出required_keys命名键、required_num_args需要的参数个数、required_key_types每个键的格式类型与required_arg_types每个槽位的格式类型分支一命名键若格式串只含命名占位符则校验右侧必须是映射Dict对每个键值对通过utils.safe_infer(arg)推断值类型再调用arg_matches_format_type比对分支二位置参数若格式串只含无名占位符则把右侧元组/容器展开为args_elts逐一推断类型并比对上报当类型不匹配时self.add_message(bad-string-format-type, nodenode, args(arg_type.pytype(), format_type))产出消息最终报错文案即Argument builtins.str does not match format type d。如果格式串同时含命名与无名占位符Pylint 会先报mixed-format-string如果右侧不是映射而是列表、函数等节点则会报format-needs-mapping。这些是 E1307 的邻居消息共同构成旧式格式化检查体系。边界与演进子类、%i/%u/%a的历史误报修复该检查在过去版本中经历过若干误报false positive修复理解这些修复能帮助你判断新版 Pylint 的行为边界4.0 版本见 doc/whatsnew/4/4.0/index.rst修复了当参数是int、float、str的子类实例如bool、IntEnum成员用%d格式化时的误报——这就是源码中is_subtype_of(builtins.int)等分支的由来4.0 版本doc/whatsnew/4/4.0/index.rst修复了对%i/%u应用于 float运行时按%d截断以及%a应用于任意非 int 类型的误报2.14 版本doc/whatsnew/2/2.14/full.rst修复了被格式化值通过变量/元组间接传入时的漏报false negative。测试文件 tests/functional/b/bad_string_format_type.py 第 59–75 行正是这些修复的回归用例import enum class Color(enum.IntEnum): RED 1 class MyFloat(float): pass %i % True # 通过bool 按 int 处理 %d %x % (Color.RED, Color.RED) # 通过IntEnum 成员按 int 处理 %f %d % (MyFloat(1.5), MyFloat(1.5)) # 通过float 子类按 float 处理 %x %s % (MyFloat(1.5), a) # [bad-string-format-type]float 不能用 %x如何启用、关闭与定位该检查默认启用E1307 属于默认开启的检查项不需要额外配置命令行关闭pylint --disablebad-string-format-type your_file.py或按编号--disableE1307配置文件关闭在pylintrc/pyproject.toml的MASTER段中写入disablebad-string-format-type代码内局部关闭在被检行上方添加注释# pylint: disablebad-string-format-type功能测试文件即使用了这种写法定位源码检查器实现位于 pylint/checkers/strings.py功能测试位于 tests/functional/b/bad_string_format_type.py查看消息文档仓库为每条消息维护了独立的文档目录本消息的说明、正反示例与相关链接分别位于 bad-string-format-type/details.rst、bad.py、good.py 与 related.rst。实践建议优先写对类型而不是依赖运行时隐式转换%d % 1虽然能运行但一旦数据来源不可控就可能抛出TypeError: %d format: a real number is required, not strE1307 帮你把这类风险前移到静态分析阶段记住三个万能格式%s、%r、%a接受任意类型不会被报错数值格式%d、%x、%f等才有严格的类型语义对无法推断类型的动态值保持预期传入函数参数、复杂表达式时Pylint 出于避免误报的考虑会放行源码与测试均明确覆盖了此行为此时建议结合类型注解或显式转换提升代码的可分析性理解检查的边界该检查只覆盖旧式%格式化str.format()与 f-string 的类型问题由其他检查项如bad-format-string、missing-format-argument-key负责不要指望 E1307 覆盖所有格式化场景。如果你正在迁移大量旧代码不妨以%格式化为切入点先让 E1307 帮你在全仓库范围内找出所有类型语义不匹配的格式化调用再逐一修正为显式类型转换或改用 f-string——这是成本最低、收益最直接的改造路径。赞分享静态分析代码质量Lint开发工具【免费下载链接】pylintIts not just a linter that annoys you!项目地址https://gitcode.com/gh_mirrors/pyl/pylint点击查看免费下载相关推荐Pylint 的 bad-format-string-keyW1300% 风格格式化字符串字典键检查详解Pylint 的 bad format string keyW1300% 风格格式化字符串字典键检查详解 导读 bad format string key静态分析代码质量Lint开发工具pylint bad-format-characterE1300检查详解识别与修复 % 旧式字符串格式化中的非法转换字符pylint bad format characterE1300检查详解识别与修复 % 旧式字符串格式化中的非法转换字符 导读 本文聚焦 Pylint 消静态分析代码质量Lint开发工具如何在内网部署本地数据库客户端Chat2DB Community 完整落地路径如何在内网部署本地数据库客户端Chat2DB Community 完整落地路径 Chat2DB Community 是本地优先的数据库客户端与 SQL 工作台数据库客户端AI 应用数据分析上一篇10分钟上手Gas Town新手必备的多智能体工作空间管理入门指南下一篇终极指南如何用pytest-mock优雅进行Python测试模拟创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考