[Python-ideas] Draft2 PEP on string interpolation

Andrew Barnert abarnert at yahoo.com
Thu Aug 27 21:25:42 CEST 2015


On Aug 27, 2015, at 12:08, Eric V. Smith <eric at trueblade.com> wrote:
> 
>> On 08/27/2015 02:30 PM, Andrew Barnert via Python-ideas wrote:
>>> On Aug 27, 2015, at 10:27, Eric V. Smith <eric at trueblade.com> wrote:
>>> 
>>>>> On 08/27/2015 11:22 AM, Mike Miller wrote:
>>>>> 
>>>>> On 08/27/2015 06:36 AM, Cody Piersall wrote:
>>>>> 
>>>>> Is the Draft PEP column of the table supposed to have both "Immediate
>>>>> Render"
>>>>> and "Deferred Render" as "Yes"? I'm hoping that's a typo, otherwise I
>>>>> don't
>>>>> understand what it means at all.
>>>> 
>>>> Yes, it supports both.  By storing all inputs to the object, it can be
>>>> rendered again, with optional changes such as overriding a value, or
>>>> escaping the input.
>>> 
>>> The problem with this auto-rendering is that the format_spec and
>>> conversion character have to make sense to __format__. For example, you
>>> couldn't do this, if value were a string:
>>> 
>>> to_html(e'<p>{value:raw}</p>')
>>> 
>>> Imagine that ":raw" is interpreted by to_html() to mean that the string
>>> does not get html escaped.
>>> 
>>> With PEP 501, the format_spec and conversion are opaque to the i-string
>>> machinery, and are only interpreted by the custom interpolation function
>>> (here, to_html()).
>> 
>> With str.format, it's the type of value that decides how to interpret the format spec. If you leave it up to the consumer of the i-string (the interpolation function) instead of the value's type, how do you handle things like numeric formats and datetime formats and so on? Would I need to do something like this:
>> 
>>    to_html(e'<p>{str(e"{value:05}"):raw}</p>')
>> 
>> Or would to_html (and every other custom interpolator) have to take things like :raw05 and parse out a format spec to pass to value.__format__?
> 
> Your interpolator would need to decide. It might never call
> value.__format__. It might invent some other protocol, like
> __html_escape__(fmt_spec). Or, it might bake-in knowledge of how to
> convert whatever types it cares about. Or another good choice would be
> to use the singledispatch module. In fact, I like singledispatch so much
> that I'm going to have to use it in an example.

But even with singledispatch, you have to write formatters for every type that just call the default format; it means you only have N+M functions to write instead of N*M (where N is the number of interpolators and M the number of types to format), but that's still a lot more than just N functions. Also, of course, the fact that you're doing it differently from the usual "just write a __format__ method" means an extra thing for people to learn, and search for.

And I think that's functionality people will almost always expect. Whether I'm dealing with a logger, an i18n library, or even a SQL DECIMAL field, I'd expect :3.5 to mean the same thing it does in str.format. So making every project write the identical code to make that true just because a small number of them won't care seems like a bad idea.

And similarly, not having a standard way to separate out the interpolator spec (which is obviously unique to every interpolator) and the format spec (which should be the same for almost every interpreter, but is different for each type) seems like it just adds confusion without adding flexibility.

Finally, the fact that, by default, handling format specs isn't done at all means it's very easy to design and implement an interpolator that doesn't do it, use it for a while, and only later realize that you need to be able to do the equivalent of :+05 and haven't left any way to do that and now have to find a clumsy way to tack it on.


More information about the Python-ideas mailing list