Template模板类

Template模板类源码:

class Template:
    """A string class for supporting $-substitutions."""

    delimiter = '$'
    # r'[a-z]' matches to non-ASCII letters when used with IGNORECASE, but
    # without the ASCII flag.  We can't add re.ASCII to flags because of
    # backward compatibility.  So we use the ?a local flag and [a-z] pattern.
    # See https://bugs.python.org/issue31672
    idpattern = r'(?a:[_a-z][_a-z0-9]*)'
    braceidpattern = None
    flags = _re.IGNORECASE

    def __init_subclass__(cls):
        super().__init_subclass__()
        if 'pattern' in cls.__dict__:
            pattern = cls.pattern
        else:
            delim = _re.escape(cls.delimiter)
            id = cls.idpattern
            bid = cls.braceidpattern or cls.idpattern
            pattern = fr"""
            {delim}(?:
              (?P<escaped>{delim})  |   # Escape sequence of two delimiters
              (?P<named>{id})       |   # delimiter and a Python identifier
              {{(?P<braced>{bid})}} |   # delimiter and a braced identifier
              (?P<invalid>)             # Other ill-formed delimiter exprs
            )
            """
        cls.pattern = _re.compile(pattern, cls.flags | _re.VERBOSE)

    def __init__(self, template):
        self.template = template

    # Search for $$, $identifier, ${identifier}, and any bare $'s

    def _invalid(self, mo):
        i = mo.start('invalid')
        lines = self.template[:i].splitlines(keepends=True)
        if not lines:
            colno = 1
            lineno = 1
        else:
            colno = i - len(''.join(lines[:-1]))
            lineno = len(lines)
        raise ValueError('Invalid placeholder in string: line %d, col %d' %
                         (lineno, colno))

    def substitute(self, mapping=_sentinel_dict, /, **kws):
        if mapping is _sentinel_dict:
            mapping = kws
        elif kws:
            mapping = _ChainMap(kws, mapping)
        # Helper function for .sub()
        def convert(mo):
            # Check the most common path first.
            named = mo.group('named') or mo.group('braced')
            if named is not None:
                return str(mapping[named])
            if mo.group('escaped') is not None:
                return self.delimiter
            if mo.group('invalid') is not None:
                self._invalid(mo)
            raise ValueError('Unrecognized named group in pattern',
                             self.pattern)
        return self.pattern.sub(convert, self.template)

    def safe_substitute(self, mapping=_sentinel_dict, /, **kws):
        if mapping is _sentinel_dict:
            mapping = kws
        elif kws:
            mapping = _ChainMap(kws, mapping)
        # Helper function for .sub()
        def convert(mo):
            named = mo.group('named') or mo.group('braced')
            if named is not None:
                try:
                    return str(mapping[named])
                except KeyError:
                    return mo.group()
            if mo.group('escaped') is not None:
                return self.delimiter
            if mo.group('invalid') is not None:
                return mo.group()
            raise ValueError('Unrecognized named group in pattern',
                             self.pattern)
        return self.pattern.sub(convert, self.template)
View Code

源码走读结论:

1、定义了一种模板格式使用“$”开头,支持$s、$$s和${s}.# Search for $$, $identifier, ${identifier}, and any bare $'s

2、定义了两个重要方法:substitute 和 safe_substitute,方法里区别就是safe多了一个异常处理,也就是说模板和替换数据个数不对应substitute方法会报KeyError,safe_substitute方法不会报错

3、substitute 和 safe_substitute可以使用key=value传参数,也可以使用dict方式传参数

例1:key=value 传值

from string import  Template

data = Template("${name}擅长的科目${project}")
new_data = data.substitute(name="张三",project="数学")

print(new_data)

结果1:

D:\Python\python.exe D:/勿动/Titen/api/commons/wz.py
张三擅长的科目数学

Process finished with exit code 0

例2:substitute

from string import  Template

data = Template("${name}擅长的科目${project}不擅长的科目${语文}")
new_data = data.substitute(name="张三",project="数学")

print(new_data)

结果2:

Traceback (most recent call last):
  File "D:\勿动\Titen\api\commons\wz.py", line 12, in <module>
    new_data = data.substitute(name="张三",project="数学")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Python\Lib\string.py", line 121, in substitute
    return self.pattern.sub(convert, self.template)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Python\Lib\string.py", line 118, in convert
    self._invalid(mo)
  File "D:\Python\Lib\string.py", line 101, in _invalid
    raise ValueError('Invalid placeholder in string: line %d, col %d' %
ValueError: Invalid placeholder in string: line 1, col 29

Process finished with exit code 1

例3:safe_substitute

from string import  Template

data = Template("${name}擅长的科目${project}不擅长的科目${语文}")
new_data = data.safe_substitute(name="张三",project="数学")

print(new_data)

结果3:

张三擅长的科目数学不擅长的科目${语文}

Process finished with exit code 0

例4:字典传值

rom string import  Template
dict1 = {"name": "张三","project":"数学"}
data = Template("${name}擅长的科目${project}")
new_data = data.safe_substitute(dict1)

print(new_data)

结果4:

张三擅长的科目数学

Process finished with exit code 0

posted on 2023-03-27 13:53  Titen  阅读(26)  评论(0编辑  收藏  举报

导航