当前位置:首页 > 文章列表 > 文章 > python教程 > Python configparser 怎样转义值里的百分号

Python configparser 怎样转义值里的百分号

来源:17golang原创 2026-10-15 04:51:06 0浏览 收藏

我在把一个带折扣比例的 INI 配置交给 configparser 读取时,最容易误判的是:百分号看起来只是普通字符,但默认解析器会先尝试把它当成插值语法。结果就是配置里的 80% 可能在读取阶段报错,而不是原样返回。

官方文档:https://docs.python.org/3/library/configparser.html

处理方法很明确:如果值里是一个字面百分号,在 BasicInterpolation 模式下写成 %%;如果确实要读取插值占位符原文,用单次 get(..., raw=True);如果整份配置都不需要插值,再初始化时使用 interpolation=None。这三种写法解决的是不同问题,不能只记住“把百分号加倍”这一条。

先区分字面百分号和插值占位符

ConfigParser 默认启用 BasicInterpolation。它允许一个配置值引用同一节或 DEFAULT 中的另一个值,形式是 %(name)s。因此百分号在这里不完全是普通文本:它既可能是插值表达式的开头,也可能是业务值中的字面字符。

例如,%(base_dir)s/cache 表示先取 base_dir 再拼接路径;而折扣、进度、税率这类值里的 % 通常只是要原样交给业务代码。两种意图混在同一个解析器里,正是报错的来源。

ConfigParser 与 BasicInterpolation 连接 80%%、百分号插值占位符、配置值和 get 方法的浅色工程蓝图说明图
图1:BasicInterpolation 的静态关系说明图;%% 表示字面百分号,%(name)s 表示配置引用。

字面百分号为什么要写成 %%

在 BasicInterpolation 中,连续两个百分号代表一个最终的字面百分号。配置文件里不要直接写 80%,而要写 80%%;读取时,get() 会返回字符串 80%。

[pricing]
# 使用两个百分号,读取后得到一个字面百分号。
discount = 80%%

[paths]
# 这里的百分号是插值标记,引用 DEFAULT 中的 base_dir。
cache = %(base_dir)s/cache

[DEFAULT]
# 插值引用的源值。
base_dir = /srv/app
import configparser

# 默认解析器启用 BasicInterpolation,会把 %% 还原为一个 %。
parser = configparser.ConfigParser()
parser.read_string("""
[DEFAULT]
# 提供给 %(base_dir)s 使用的基础目录。
base_dir = /srv/app

[pricing]
# 配置文本中的 %% 表示一个字面百分号。
discount = 80%%

[paths]
# 这个占位符会引用 DEFAULT 的 base_dir。
cache = %(base_dir)s/cache
""")

# 读取后的值已经完成插值,但 discount 仍是普通字符串。
print(parser.get("pricing", "discount"))
print(parser.get("paths", "cache"))

输出分别是 80% 和 /srv/app/cache。这里要注意,%% 只是在解析阶段表示一个字面百分号;它不是 Python 字符串格式化,也不是正则表达式转义。

用 Python 写入配置时也遵循同一规则

如果配置不是从文件读入,而是由程序通过映射接口或 set() 写入,仍然要按照当前解析器的插值语义组织值。将字面百分号存成 %%,读取时才能稳定得到一个 %。

import configparser
from io import StringIO

# 这个解析器保留默认的 BasicInterpolation 行为。
parser = configparser.ConfigParser()

# 写入字面百分号时使用 %%,不要直接把单个 % 当成普通文本。
parser["service"] = {"quota": "80%%"}

# 将配置写入内存文本,便于后续交给同样的解析器读取。
buffer = StringIO()
parser.write(buffer)

# 重新读取,模拟文件落盘后再次加载的过程。
loaded = configparser.ConfigParser()
loaded.read_string(buffer.getvalue())

# 读取阶段把 %% 还原成一个字面百分号。
print(loaded.get("service", "quota"))

这个规则的好处是“写入”和“读取”保持同一套约定。如果一个组件直接生成 INI,另一个组件却用原始文本的想法去拼值,就容易把 %% 当成最终内容,进而在业务层得到两个百分号。

只想拿原文时使用 raw=True

有些场景不是想把插值关闭,而是要检查配置原文、展示模板,或者把下一阶段才处理的占位符交给别的系统。这时不要修改整个解析器,只在读取动作上加 raw=True。

import configparser

# 读取包含插值占位符的配置文本。
parser = configparser.ConfigParser()
parser.read_string("""
[DEFAULT]
# 这个值会被 BasicInterpolation 作为源值使用。
root = /srv/app

[template]
# 这里保存的是一个需要暂缓处理的占位符。
path = %(root)s/cache
""")

# 默认读取会展开 %(root)s。
expanded = parser.get("template", "path")

# raw=True 只影响本次读取,返回尚未展开的原文。
raw_value = parser.get("template", "path", raw=True)

print(expanded)
print(raw_value)

raw=True 的作用域是本次取值,不会把同一个解析器改成“以后都不插值”。如果只是在日志、模板检查或迁移脚本中偶尔需要原文,它比全局关闭插值更安全。

什么时候应该关闭 interpolation

如果整份配置都把百分号、括号和其他格式符号当作普通文本,不需要 %(name)s 这种引用关系,可以在初始化时关闭插值:

import configparser

# 关闭所有插值,让配置值按原文返回。
parser = configparser.ConfigParser(interpolation=None)
parser.read_string("""
[metrics]
# 单个百分号不再被当成插值语法。
rate = 80%

[template]
# 占位符也会作为普通文本保留。
path = %(root)s/cache
""")

# 两个值都不做插值展开。
print(parser.get("metrics", "rate"))
print(parser.get("template", "path"))

也可以使用 RawConfigParser,它的默认插值行为就是关闭的。不过在团队代码里,显式写出 ConfigParser(interpolation=None) 往往更容易让读者看出这是一个有意的解析策略,而不是忘了配置。

INI 文本经过 ConfigParser 后由 get、raw=True、interpolation=None 和 RawConfigParser 连接到原始百分号的工程蓝图说明图
图2:读取策略的静态关系说明图;局部原文读取与全局关闭插值承担不同职责。

单个百分号报错时怎样定位

如果配置中写了单个 %,读取时可能出现 InterpolationSyntaxError;如果写成了一个插值引用但对应键不存在,则通常会出现 InterpolationMissingOptionError。排查时先问三个问题:这个百分号是不是业务字面量、当前读取是否需要展开、值是由文件还是代码生成的。

import configparser

# 保留默认插值,用异常类型区分语法问题和缺失引用。
parser = configparser.ConfigParser()
parser.read_string("""
[service]
# 这里故意使用字面百分号的错误写法,读取时会触发插值解析错误。
rate = 80%
""")

try:
    # 读取动作才会真正触发插值处理。
    print(parser.get("service", "rate"))
except configparser.InterpolationError as exc:
    # 把节名、键名和解析异常一起记录,便于定位来源配置。
    print(type(exc).__name__, exc.section, exc.option)

如果该字段就是字面值,修正配置为 80%%;如果需要检查原文,临时使用 raw=True;如果所有字段都不需要插值,才把解析器改成 interpolation=None。不要为了绕过一个字段的问题,把全局解析规则随意改掉。

三种写法怎么选

需求推荐写法读取结果
配置值需要一个字面百分号80%%80%
只在一次读取中保留插值原文get(section, option, raw=True)返回未展开文本
整份配置都不使用插值ConfigParser(interpolation=None)所有值按原文读取

我实际更倾向于把选择写在创建解析器或读取函数附近,而不是只在注释里说“这里有百分号”。这样后续维护者能从代码直接看到:该值是要参与插值、暂时保留模板,还是完全按原文处理。

常见问题

为什么 80% 不能直接读取?

因为默认 ConfigParser 使用 BasicInterpolation,百分号可能被当成插值语法开头。字面百分号应写成 80%%。

raw=True 会永久关闭插值吗?

不会。它只影响当前这次 get() 或相关读取调用,后续普通读取仍会按照解析器默认规则展开。

什么时候用 RawConfigParser?

当配置格式本身明确不需要插值时可以使用。若项目更强调可读性和显式意图,ConfigParser(interpolation=None) 通常更容易被维护者理解。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python asyncio.PriorityQueue 怎样保持相同优先级的稳定顺序Python asyncio.PriorityQueue 怎样保持相同优先级的稳定顺序
上一篇
Python asyncio.PriorityQueue 怎样保持相同优先级的稳定顺序
Python dataclass ClassVar 怎样排除类级配置字段
下一篇
Python dataclass ClassVar 怎样排除类级配置字段
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    477次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    534次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    554次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    506次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    327次使用