[Python-ideas] String interpolation for all literal strings

Nick Coghlan ncoghlan at gmail.com
Fri Aug 7 14:31:50 CEST 2015


On 7 August 2015 at 22:12, Eric V. Smith <eric at trueblade.com> wrote:
> On 8/7/2015 7:52 AM, Eric V. Smith wrote:
>> So (reverting to Python syntax, with the f-string syntax), in addition
>> to converting directly to a string, there's a way to go from:
>>
>> f'abc{expr1:spec1}def{expr2:spec2}ghi'
>>
>> to:
>>
>> ('abc{0:spec1}def{1:spec2}ghi', (value-of-expr1, value-of-expr2))
>>
>> The general idea is that you now have access to an i18n-able string, and
>> the values of the embedded expressions as they were evaluated "in situ"
>> where the f-string literal was present in the source code.
>> Y
>> ou can imagine the f-string above evaluating to a call to:
>>
>> __interpolate__('abc{0:spec1}def{1:spec2}ghi', (value-of-expr1,
>> value-of-expr2))
>>
>> The default implementation of __interpolate__ would be:
>>
>> def __interpolate__(fmt_str, values):
>>     return fmt_str.format(*values)
>
> I should add that it's unfortunate that this builds a string for
> str.format() to use. The f-string ast generator goes through a lot of
> hassle to parse the f-string and extract the parts. For it to then build
> another string that str.format would have to immediately parse again
> seems like a waste.
>
> My current implementation of f-strings would take the original f-string
> above and convert it to:
>
> ''.join(['abc', expr1.__format__('spec1'), 'def',
>          expr2.__format__(spec2), 'ghi'])
>
> Which avoids re-parsing anything: it's just normal function calls.
> Making __interpolate__ take a tuple of literals and a tuple of (value,
> fmt_str) tuples seems like giant hassle to internationalize, but it
> would be more efficient in the normal case.

Perhaps we could use a variant of the string.Formatter.parse iterator
format: https://docs.python.org/3/library/string.html#string.Formatter.parse
?

If the first arg was a pre-parsed format_iter rather than a format
string, then the default interpolator might look something like:

    _converter = string.Formatter().convert_field

    def __interpolate__(format_iter, expressions, values):
        template_parts = []
        # field_num, rather than field_name, for speed reasons
        for literal_text, field_num, format_spec, conversion in format_iter:
            template_parts.append(literal_text)
            if field_num is not None:
                value = values[field_num]
                if conversion:
                    value = _converter(value, conversion)
                field_str = format(value, format_spec)
                template_parts.append(field_str)
        return "".join(template_parts)

My last il8n example called string.Formatter.parse() anyway, so it
could readily be adapted to this model.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list