在Python中子类化string.Template的示例?

23 投票
1 回答
7356 浏览
提问于 2025-04-15 13:53

我一直没能找到一个好的例子,说明如何在Python中对string.Template进行子类化,尽管我在文档中看到过很多提到这个的地方。

网上有没有相关的例子呢?

我想把$这个符号换成其他字符,可能还想修改一下用于标识符的正则表达式。

1 个回答

33

来自Python的文档

高级用法:你可以创建模板的子类,以自定义占位符的语法、分隔符字符,或者用于解析模板字符串的整个正则表达式。要做到这一点,你可以重写以下类属性:

  • delimiter – 这是描述占位符引入分隔符的字符串。默认值是$。注意,这个值不应该是正则表达式,因为实现会在需要时对这个字符串调用re.escape()。

  • idpattern – 这是描述非大括号占位符模式的正则表达式(大括号会自动添加)。默认值是正则表达式[_a-z][_a-z0-9]*。

示例:

from string import Template

class MyTemplate(Template):
    delimiter = '#'
    idpattern = r'[a-z][_a-z0-9]*'

>>> s = MyTemplate('#who likes $what')
>>> s.substitute(who='tim', what='kung pao')
'tim likes $what'

在Python 3中:

在3.2版本中新增。

另外,你可以通过重写类属性pattern来提供整个正则表达式模式。如果这样做,值必须是一个具有四个命名捕获组的正则表达式对象。这些捕获组对应于上面给出的规则,以及无效占位符规则:

  • escaped – 这个组匹配转义序列,例如默认模式中的$$。
  • named – 这个组匹配没有大括号的占位符名称;它不应该在捕获组中包含分隔符。
  • braced – 这个组匹配被大括号包围的占位符名称;它不应该在捕获组中包含分隔符或大括号。
  • invalid – 这个组匹配任何其他分隔符模式(通常是单个分隔符),并且它应该在正则表达式中最后出现。

示例:

from string import Template
import re

class TemplateClone(Template):
    delimiter = '$'
    pattern = r'''
    \$(?:
      (?P<escaped>\$) |   # Escape sequence of two delimiters
      (?P<named>[_a-z][_a-z0-9]*)      |   # delimiter and a Python identifier
      {(?P<braced>[_a-z][_a-z0-9]*)}   |   # delimiter and a braced identifier
      (?P<invalid>)              # Other ill-formed delimiter exprs
    )
    '''

class TemplateAlternative(Template):
    delimiter = '[-'
    pattern = r'''
    \[-(?:
       (?P<escaped>-) |            # Expression [-- will become [-
       (?P<named>[^\[\]\n-]+)-\] | # -, [, ], and \n can't be used in names
       \b\B(?P<braced>) |          # Braced names disabled
       (?P<invalid>)               #
    )
    '''

>>> t = TemplateClone("$hi sir")
>>> t.substitute({"hi": "hello"})
'hello sir'

>>> ta = TemplateAlternative("[-hi-] sir")
>>> ta.substitute({"hi": "have a nice day"})
'have a nice day sir'
>>> ta = TemplateAlternative("[--[-hi-]-]")
>>> ta.substitute({"hi": "have a nice day"})
'[-have a nice day-]'

显然,你也可以选择省略任何正则表达式组escapednamedbracedinvalid来禁用它。

撰写回答