[Python-ideas] Escaped braces in format specifiers

Ken Kundert python-ideas at shalmirane.com
Tue May 15 02:41:36 EDT 2018

The syntax for formatted string literals is given here:

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))
         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
    SyntaxError: invalid syntax


    >>> 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.


More information about the Python-ideas mailing list