New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Default values for string.Template #57382
Comments
This patch allows you to define default values for a string.Template, which is useful when you need to use a lot some values, but sometimes other values. for example: >>> from string import Template
>>> s = Template("${user} made me a ${flavor} cake.", default={"user":"Dennis"})
>>> s.substitute(flavor="vanilla")
'Dennis made me a vanilla cake.'
>>> s.substitute(user="Ken", flavor="chocolate")
'Ken made me chocolate cake.' |
Thanks for your interest in Python. Can you repost your code as a diff? (See the devguide for more info) |
Here is my code as a diff |
Thanks for the patch. It mostly looks good; a detailed review follow. + The constructor takes two arguments, the first is the template string and Like :meth:`substitute`, except that if placeholders are missing from
- *mapping* and *kwds*, instead of raising a :exc:`KeyError` exception, the
- original placeholder will appear in the resulting string intact. Also,
- unlike with :meth:`substitute`, any other appearances of the ``$`` will
- simply return ``$`` instead of raising :exc:`ValueError`.
+ *mapping*, *kwds* and *default*, instead of raising a :exc:`KeyError`
default is not an argument, so *foo* markup is misleading. Either use “the default values given to the constructor” or just “self.default”. + exception, the original placeholder will appear in the resulting string + .. attribute:: default
+
+ This is the optional dictionary object passed to the constructor's
+ *template* argument.
I’m not a native English speaker, but “passed to” seems wrong here (and in the other attribute’s doc). I’d say “passed as the *default* argument”.
- def __init__(self, template):
+ def __init__(self, template, default={}):
Binding a mutable object to a local name at compile time is not good: All instances created without *default* argument will share the same dict, so editions to onetemplate.default will change anothertemplate.default too. The common idiom is to use None as default value and add this: self.default = default if default is not None else {} |
Adding Georg, maintainer of the string module, to the nosy list. If he approves the idea, you can go ahead and complete your patch. |
diff updated |
A "light" version of diff added (rewrapped content is replaced by "[rewrapping]") |
This looks like a reasonable use case. That being said, I question whether the defaults should be attached directly to the template instance or whether they should be part of the substitution method. FWIW, there already have a couple of other ways to do it: >>> from string import Template
>>> s = Template("${user} made me a ${flavor} cake.")
>>> default = {"user":"Dennis"}
>>> s.substitute(default, flavor='vanilla')
'Dennis made me a vanilla cake.'
>>> s.substitute(default, user='Ken', flavor='vanilla')
'Ken made me a vanilla cake.'
>>> from collections import ChainMap
>>> s.substitute(ChainMap(dict(flavor='vanilla'), default))
'Dennis made me a vanilla cake.' |
When you are using a lot of string templates like I am doing, I think it's better if the defaults is attached directly to the template instance. This: |
Barry, any thoughts? |
When I need defaults, I make them part of the mapping that gets passed into .substitute() and .safe_substitute(). It doesn't feel to me like it's necessary to attach them to the Template instance. Also, couldn't you just subclass string.Template if you wanted defaults? OTOH, since it can be done in a backward compatible way, I guess I'm -0 on the change. |
It looks like a doc update to mention the excellent ChainMap class would be a good thing. Bfontaine, are you happy with using a Template subclass or changing your code slightly to have defaults outside of the Template objects, or do you still think the class should be changed? We could run this by the python-ideas mailing list. |
If the Template defaults should be attached directly to the template instance, then they should be attached directly to the string instance, for classic and modern string formatting. And this obviously is absurd. I agree with Éric, to mention ChainMap class in the string formatting documentation will be enough. |
I'm looking at this issue again with an eye toward Python 3.4. Raymond describes what I think is a reasonable way to use defaults: >>> x = Template('$foo $bar')
>>> defaults = dict(foo='one', bar='two')
>>> x.substitute(defaults)
'one two'
>>> x.substitute(defaults, bar='three')
'one three'
>>> x.substitute(defaults, foo='nine', bar='three')
'nine three' (The implementation actually uses ChainMap.) Now, to address Bfontaine's complaint about passing around tuples, observe that Template instances are Just Instances, so you can always do this: >>> x = Template('$foo $bar')
>>> x.defaults = defaults
>>> x.substitute(x.defaults, foo='nine', bar='three')
'nine three' IOW, just stash your defaults on the instance and pass the instance around. Does the Template class actually need more built-in support for defaults? I'm inclined to close this as Won't Fix. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: