How to specify a default value for unspecified variable in Python string templates?

134 Views Asked by At

Consider the following code

from string import Template
s = Template('$a $b')

print(s.safe_substitute(a='hello'))  # $b is not substituted
print(s.substitute(a='hello'))  # raise error

What I want is that I can specified a default value for all the unspecified variables in the template, for example, an empty string ''.

The reason I need this feature is there is a case that both template and variables are provided by users. They may provided some placeholders in the template string as an injection point in case someone else may need to use them, but if the user don't provide value for it those placeholders should be ignore. And I don't need to specify different default values for different variables, but just a common default value for all missing variables.

I don't have to stick to the string template module, but I don't want to use heavy solution like jinja2 either. I just want to have a lightweight template soltuion to get things done.

The method to provide a default dictionary doesn't work in my case as the template is provided by other users, so I don't know the possbile vaiables before hand.

2

There are 2 best solutions below

6
matszwecja On BEST ANSWER

As stated in documentation, safe_substitute and substitute accept values in 2 forms - as keyword arguments, as you are doing, or as a mapping dict. It also assures us that "When both mapping and kwds are given and there are duplicates, the placeholders from kwds take precedence". With this in mind, we can use this mapping dict to provide default values for all variables, and ones we pass explicitly as keyword will get overwritten with new values.

from string import Template
s = Template('$a $b')


defaults = {'a': 'a_default', 'b': 'b_default'}

print(s.safe_substitute(defaults, a='hello'))  # hello b_default
print(s.substitute(defaults, a='hello'))  # hello b_default

If all the identifiers should use same default value, you can use a defaultdict with the same method.

from string import Template
from collections import defaultdict
s = Template('$a $b')

defaults = defaultdict(lambda: '')

print(s.safe_substitute(defaults, a='hello'))  # $b is not substituted
print(s.substitute(defaults, a='hello'))  # raise error
10
Barmar On

Use get_identifiers() to get all the variables in the template. Then if any variables are missing in the user-supplied data, you can fill in the default values from this.

def substitute_with_default(template: Template, values: dict, default: str = '') -> str:
    defaults = dict.fromkeys(template.get_identifiers(), default)
    return template.substitute(defaults | values)

print(substitute_with_default(Template('$a $b'), {'a': 'hello'}))

This method requires Python 3.11.