On Sat, May 19, 2018 at 07:06:41AM -0400, Eric V. Smith wrote:
On 5/19/2018 1:56 AM, Ken Kundert wrote:
On Tue, May 15, 2018 at 04:23:26PM -0400, Eric V. Smith wrote:
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
Eric, You say that recursive format specs are supported to a depth of 1, but it does not seem like true recursion to me. If it were true recursion, wouldn't the escaped braces be interpreted properly inside the format spec, just as they are in the literal portion of the f-string?
Is there some reason why escaped braces are not supported in the format specs?
Consider the following example:
>>> class myclass: ... def __format__(self, fmt_spec): ... return 'fmt_spec: ' + fmt_spec
>>> d = myclass() >>> x = 3
>>> print('1: ext={{x}} {d:int={{x}}}'.format(d=d)) 1: ext={x} fmt_spec: int={x}
>>> print(f'2: ext={{x}} {d:int={{x}}}') 2: ext={x} fmt_spec: int={3}
>>> print(f'3: ext={set([x])} {d:int={set([x])}}') 3: ext={3} fmt_spec: int={3}
In each case, the same substring is found in the literal portion (ext) of the format string and in the format spec (int).
In case 1, the format string is passed to a format method and the substring is {{x}}. In both cases, the double braces are interpreted as escaped braces, and both are converted to '{x}' in the final printed result.
In case 2, the format string is an f string. The substring is still {{x}}. The first instance of {{x}} is found in the literal portion of the format string and the double braces are interpreted as escaped braces. It expands to {x} like in the first case. However, the second instance is found in the format spec, and this case the outer braces are stripped off and what is left over is treated as a Python expression. Here {x} is treated as a set literal containing one value, x. Since x is 3, the value of int is {3}.
Case 3 confirms the interpretation of case 2 by simply replacing {x} with an alternate way of specifying a set literal that contains a single value. In this case there are no double braces and so both instances are treated the same, both expand to {3}.
So the format method supports escaped braces in both the literal part of the format string and the format spec. f-strings supports escaped braces in the literal part of the format string, but in the format spec the outer level of braces are stripped off and what remains is interpreted as a Python expression.
Is there some benefit to this difference?
Is the difference you're seeing just in how f-strings and str.format() differ in evaluating expressions? str.format() isn't evaluating "int={x}", which makes sense to me. It never evaluates expressions, by design, it just treats strings as literals. If it did evaluate expressions, there's too great a chance of code being evaluated from user-defined strings.
Eric
Eric, My example does highlight the fact that f-strings do evaluate the embedded expressions while str.format() does not, but that is not the point I was trying to make. The substring 'int={{x}}' has two possible interpretations, it is either a string that contains escaped braces and when the escaping is processed becomes 'int={x}', or the outer braces signal an embedded expression, the expression being {x}, a set literal, and when interpolated the substring becomes 'int={3}'. My point was that str.format() uses the first interpretation for both ext and int, but f-strings use the first interpretation for ext and the second interpretation for int. Using the second interpretation for int in the f-string seems inconsistent. Specifically, int and ext are interpreted differently in the f-string, and int is interpreted differently by str.format() and the f-string. This difference does not seem to provide any benefit, so why does it exist? In other words, why aren't the escaped braces supported in the format_spec of f-strings? -Ken