资讯详情

Python模板的使用详细讲解

📅 2026/10/11 12:21:43 | 华诺云谱 👁 阅读
Python模板的使用详细讲解
前言Python 模板这个说法在中文语境里其实是有歧义的至少对应三样不同的东西一是标准库string模块里的string.Template类用$名字做占位符二是 f-string即f{name}这种格式化字符串字面量三是 Python 3.14 才加入的模板字符串字面量t-stringPEP 750写法是t...。三者不是一回事混着讲最容易被带偏。本文聚焦第一个——string.Template它是三者里唯一运行时构造、字段来自外部数据的通用方案然后再说清它和另外两者的取舍。另一个常见误解是认为Template只是str.format的花哨写法。恰恰相反str.format会解析占位符里的属性访问和下标模板内容若来自不可信来源就有泄露内部对象的风险而Template只做纯文本替换占位符只认简单的标识符不访问属性也不取下标因此在模板由外部提供的场景里它是更稳妥的选择。本文代码基于 Python 3.8 及以上。string.Template在 Python 2 里也存在但 Python 2.7 已于 2020 年 1 月 1 日停止维护本文一律用 Python 3 的写法。一、Template 的基本用法string.Template的构造签名是Template(template)接收一个模板字符串。两个替换方法的签名按官方文档是substitute(mapping{}, /, **kwds)safe_substitute(mapping{}, /, **kwds)注意mapping后面那个/它是仅位置参数positional-only只能用位置传写substitute(mappingd)会被当成一个叫mapping的关键字占位符。# 适用于 Python 3.8from string import Templatet Template($who 喜欢 $what)print(t.substitute(who小明, whatPython)) # 小明 喜欢 Pythonprint(t.substitute({who: 小红, what: C})) # 小红 喜欢 C占位符有四种写法写法含义$name简单占位符名字后不能紧跟字母或数字${name}带花括号名字边界明确$$一个字面量$$100非法占位符会报错花括号主要用于占位符后面还要紧跟字符的场合# 适用于 Python 3.8from string import Template# 不加花括号时$name 后面若紧跟标识符字符会解析错误或歧义print(Template(${name}3000).substitute(nameAI)) # AI3000二、substitute 与 safe_substitute 的区别两者最大的差别在缺键时的行为。substitute在占位符对应的键缺失时抛KeyError遇到非法占位符比如$100时抛ValueError。safe_substitute则尽量返回一个可用字符串缺的占位符原样保留其他位置的$也原样返回$不会抛异常。官方文档给的例子很能说明问题# 适用于 Python 3.8from string import Templated {who: tim}print(Template($who likes $what).substitute(d))# KeyError: whatprint(Template($who likes $what).safe_substitute(d))# tim likes $whatprint(Template(Give $who $100).substitute(d))# ValueError: Invalid placeholder in string: line 1, col 11safe_substitute名字里带 safe但官方也提醒了另一面它会静默忽略畸形模板包括悬空的$、不配对的括号和非法标识符。也就是说它不会报错但可能悄悄给你一个带$what的字符串。如果模板必须严格正确用substitute更合适。三、校验模板is_valid 与 get_identifiersPython 3.11 起Template增加了两个方法可以在替换前先检查模板is_valid()模板里有会让substitute()抛ValueError的非法占位符时返回Falseget_identifiers()按首次出现顺序返回模板中合法标识符的列表非法标识符被忽略# 适用于 Python 3.11from string import Templatet Template($a and ${b})print(t.is_valid()) # Trueprint(t.get_identifiers()) # [a, b]bad Template($a and $1)print(bad.is_valid()) # Falseprint(bad.get_identifiers()) # [a]低版本没有这两个方法可以在替换时用safe_substitute兜底或自己用正则粗略校验但不如 3.11 的官方实现准确。四、自定义分隔符子类化 TemplateTemplate允许通过类属性改写语法官方列出的可覆盖属性有类属性默认值作用delimiter$引占位符的分隔字符idpattern(?a:[_a-z][_a-z0-9]*)非花括号占位符的正则braceidpatternNone花括号内的占位符正则3.7 起flagsre.IGNORECASE编译模板正则时的标志# 适用于 Python 3.8from string import Templateclass BangTemplate(Template):delimiter !print(BangTemplate(你好 !name).substitute(name世界))# 你好 世界有个硬性限制delimiter必须在子类的类命名空间里设定实例创建之后再改是无效的。文档明确说明不能在类创建后修改分隔符。五、Template 与其他格式化方式的取舍方式占位符求值时机适合场景Template$name运行时替换模板来自外部、只做纯文本替换f-string{expr}写代码时求值代码里固定格式性能与可读性好str.format{0}/{name}运行时替换需要位置参数、格式规格t-string3.14 起{expr}生成结构对象需要自定义后处理如安全拼 SQLf-string 从 3.6 起可用调试用的说明符如f{x}是 3.8 加的3.12 起同名引号可以嵌套、表达式里可以有反斜杠PEP 701。t-string 是 3.14 的新特性用t前缀求值得到的是模板对象而不是字符串字符串内容必须显式拼接。这些都不属于string.Template写文章时不要混为一谈。实战用 Template 渲染一份通知下面把Template用在一个典型场景——模板文本从配置里读入用一组数据去填充。# 适用于 Python 3.8from string import TemplateTEMPLATE_TEXT \亲爱的 $name您的订单 $order_id 已于 $date 发出预计 $days 天内送达。共 $price 元。祝好$companydef render(data):t Template(TEMPLATE_TEXT)# 先校验必须字段是否齐全缺了就明确报错而不是产出残缺文本needed set(t.get_identifiers())missing needed - set(data)if missing:raise ValueError(f缺少字段{sorted(missing)})return t.substitute(data)notice render({name: 小王,order_id: A1024,date: 2026-10-07,days: 3,price: 199,company: 示例商城,})print(notice)get_identifiers()需要 3.11 及以上若目标是更早版本把校验那几行换成safe_substitute并在结果里检查是否还残留$或者用substitute直接让KeyError暴露问题。常见坑点把占位符写成花括号❌Template({name}).substitute(namex)得不到替换输出仍是{name}✅Template($name).substitute(namex)Template认的是$缺键时用 substitute 直接崩❌Template($a $b).substitute(a1)→KeyError: b✅ 要么用safe_substitute要么先get_identifiers()校验字段齐全金额里的$忘了转义❌Template($price 美元优惠 $5).substitute(price10)→ 因为$5是非法占位符而抛ValueError✅ 写成$$5输出才是字面量$5把 mapping 当关键字参数传❌t.substitute(mappingd)因为mapping是仅位置参数这会被当成替换一个名叫mapping的占位符✅t.substitute(d)位置传参以为 safe_substitute 永远安全❌ 用safe_substitute渲染后直接入库结果模板里的$what原样进了数据✅ 需要严格性时用substitute用safe_substitute就要在结果里显式检查残留占位符实例化后再改分隔符❌t Template(...); t.delimiter !改了不生效✅ 在Template的子类里通过类属性设定delimiter用 str.format 渲染外部模板❌ 直接把外部模板交给str.format占位符可写属性访问可能读到不该暴露的对象✅ 外部模板用string.Template它只做标识符级替换不解析属性与下标照抄 Python 2 的写法❌ 用print语句、把u...当必需前缀✅ Python 3 里print是函数字面量默认就是 UnicodePython 2.7 已于 2020 年 1 月 1 日 EOL总结要点结论占位符语法$name、${name}$$表示字面量$缺键行为substitute抛KeyErrorsafe_substitute原样保留非法占位符substitute抛ValueError如$100校验方法is_valid()、get_identifiers()3.11 起改分隔符通过子类的类属性delimiter设定安全性只做纯文本替换比str.format更适合外部模板string.Template的价值不在于功能多强而在于边界清楚占位符规则简单、不解析复杂表达式、行为可预期。当模板文本由用户或配置文件提供、而你只想要一次纯粹的名字替换时它是标准库里最省心的那一件工具。至于 f-string 和 3.14 的 t-string它们解决的是另外的问题别和Template混为一谈。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑