[Python-ideas] Escaped braces in format specifiers
Eric V. Smith
eric at trueblade.com
Tue May 15 16:23:26 EDT 2018
I'm busy at the sprints, so I don't have a lot of time to think about this.
However, let me just say that recursive format specs are supported, to a
depth of 1.
>>> width=10
>>> f'{"test":{width}}'
'test '
So first the string is basically expanded to:
f'{"test":10}'
Then the string is formatted again to produce the final result.
That is why the braces must match: they're being used for recursive
format specs. There's no mechanism for having braces that aren't
inspected by the f-string machinery.
Eric
On 5/15/18 2:41 AM, Ken Kundert wrote:
> The syntax for formatted string literals is given here:
> https://docs.python.org/3/reference/lexical_analysis.html#f-strings
>
> If you were to examine this carefully, you would see that a format_spec (the
> part within the braces but after the colon) can be empty or it can consist of
> literal characters and replacement fields. For example:
>
> f"result: {value:{width}.{precision}}"
>
> In this case '{width}.{precision}' is the format_spec, it consists of two
> replacement fields, {width} and {precision}, and one literal character, '.'.
>
> The definition of literal character includes all characters except braces.
> Presumably excluding braces makes it easier to distinguish the replacement
> fields. However, replacement fields are also used in the f_string itself, but
> in that case escaped braces are explicitly added to the list of valid symbols.
>
> I think the fact that one cannot include braces in the format_spec is an
> unnecessary and undesirable restriction.
>
> As an example of where it would be useful to allow braces in the format_spec,
> consider this simple example:
>
> >>> class mydict(dict):
> ... def __format__(self, template):
> ... return ''.join(
> ... template.format(v, k=k, v=v) for k, v in self.items()
> ... )
>
> >>> accounts = mydict(checking=4256.78, savings=12000, brokerage=24685.5)
> >>> print('Accounts:\n {0:{{k:>9s}}: ${{v:>9,.2f}}\n }'.format(accounts))
> Accounts:
> checking: $ 4,256.78
> savings: $12,000.00
> brokerage: $24,685.50
>
> In this example, the format_spec is itself treated as a format string, which
> allows a recursive specification of the string format.
>
> If you try this example in Python3.6 you will find that it works, but it should
> not because the format_spec contains escaped braces. However, the fact that it
> works appears be be a happy accident. Things break if the escaped braces are not
> balanced (thanks to Thomas Jollans for finding this). Furthermore, things break
> in a different manner when an f-string is used. For example:
>
> >>> print(f'Accounts:\n {accounts:{{k:>9s}}: ${{v:>9,.2f}}\n }')
> File "<fstring>", line 1
> ({k:>9s})
> ^
> SyntaxError: invalid syntax
>
> or:
>
> >>> print(f'Accounts:\n {accounts:{{k}}: ${{v}}\n }')
> File "tryit", line 12, in <module>
> print(f'Accounts:\n {accounts:{{k}}: ${{v}}\n }')
> NameError: name 'k' is not defined
>
> Oddly, the f-string still raises the NameError even if both k and v are
> explicitly defined.
>
> At a minimum it would be good to improve the error messages that are produced
> when escaped braces are included in the format_spec. Most of the error messages
> that are given, if they are given at all, are misleading. None are as simple as:
>
> SyntaxError: escaped braces are not allowed in a format spec.
>
> But rather than improve the error messages, I think we should consider simply
> allowing escaped braces in the format_spec. Doing so enables the neat idea of
> recursive format strings. But even if you don't like that idea, it would be nice
> to remove this rather rather odd restriction and would make the behavior of
> f-strings and the format method more consistent.
>
> -Ken
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
More information about the Python-ideas
mailing list