<div dir="ltr">Thanks, Eric! You're addressing all my concerns and you're going exactly where I wanted this to go. I hope that you will find the time to write up a PEP; take your time. Regarding your [1], let's not consider unevaluated f-strings as a feature; that use case is sufficiently covered by the existing str.format().<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jul 21, 2015 at 1:58 PM, Eric V. Smith <span dir="ltr"><<a href="mailto:eric@trueblade.com" target="_blank">eric@trueblade.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 7/21/2015 2:05 AM, Guido van Rossum wrote:<br>
> And now that I think about it, it's somewhat more complex than just<br>
> expanding the expression. In .format(), this:<br>
> '{a[0]}{b[c]}'<br>
> is evaluated roughly as<br>
> format(a[0]) + format(b['c'])<br>
><br>
><br>
> Oooh, this is very unfortunate. I cannot support this. Treating b[c] as<br>
> b['c'] in a "real" format string is one way, but treating it that way in<br>
> an expression is just too weird.<br>
<br>
</span>I think you're right here, and my other emails were trying too much to<br>
simplify the implementation and keep the parallels with str.format().<br>
The difference between str.format() and f-strings is that in<br>
str.format() you can have an arbitrarily complex expression as the<br>
passed in argument to .format(). With f-strings, you'd be limited to<br>
just what can be extracted from the string itself: there are no<br>
arguments to be passed in. So maybe we do want to allow arbitrary<br>
expressions inside the f-string.<br>
<br>
For example:<br>
<br>
'{a.foo}'.format(a=b[c])<br>
<br>
If we limit f-strings to just what str.format() string expressions can<br>
represent, it would be impossible to represent this with an f-string,<br>
without an intermediate assignment.<br>
<br>
But if we allowed arbitrary expressions inside an f-string, then we'd have:<br>
f'{b[c].foo}'<br>
<br>
and similarly:<br>
'{a.foo}'.format(a=b['c'])<br>
would become:<br>
f'{b["c"].foo}'<br>
<br>
But now we'd be breaking compatibility with str.format(). Maybe it's<br>
worth it, though. I can see 80% of the uses of str.format() being<br>
replaced by f-strings. The remainder would be cases where format strings<br>
are passed in to other functions. I do this a lot with custom logging [1].<br>
<br>
The implementation complexity goes up by allowing arbitrary expressions.<br>
Not that that is necessarily a reason to drive a design decision.<br>
<br>
For example:<br>
f'{a[2:3]:20d}'<br>
<br>
We need to extract the expression "a[2:3]" and the format spec "20d". I<br>
can't just scan for a colon any more, I've got to actually parse the<br>
expression until I find a "}", ":", or "!" that's not part of the<br>
expression so that I know where it ends. But since it's happening at<br>
compile time, I surely have all of the tools at my disposal. I'll have<br>
to look through the grammar to see what the complexities here are and<br>
where this would fit in.<br>
<span class=""><br>
> So given that, I think we should just support what .format() allows,<br>
> since it's really not quite as simple as "evaluate the expression inside<br>
> the braces".<br>
><br>
> Alas. And this is probably why we don't already have this feature.<br>
<br>
</span>Agreed. So I think it's either "don't be compatible with str.format<br>
expressions" or "abandon the proposed f-strings".<br>
<span class=""><br>
> > Not sure what you mean by "implicit merging" -- if you mean literal<br>
> > concatenation (e.g. 'foo' "bar" == 'foobar') then I think it should be<br>
> > allowed, just like we support mixing quotes and r''.<br>
><br>
> If I understand it, I think the concern is:<br>
><br>
> f'{a}{b}' 'foo{}' f'{c}{d}'<br>
><br>
> would need to become:<br>
> f'{a}{b}foo{{}}{c}{d}'<br>
><br>
> So you have to escape the braces in non-f-strings when merging strings<br>
> and any of them are f-strings, and make the result an f-string. But I<br>
> think that's the only complication.<br>
><br>
><br>
> That's possible; another possibility would be to just have multiple<br>
> .format() calls (one per f'...') and use the + operator to concatenate<br>
> the pieces.<br>
<br>
</span>Right. I think the application would actually use _PyUnicodeWriter to<br>
build the string up, but it would logically be equivalent to:<br>
<br>
'foo ' f'b:{b["c"].foo:20d} is {on_off}' ' bar'<br>
<br>
becoming:<br>
<br>
'foo' + 'b:' + format(b["c"].foo, '20d') + ' is ' +<br>
format(on_off) + ' bar'<br>
<br>
At this point, the implementation wouldn't call str.format() because<br>
it's not being used to evaluate the expression. It would just call<br>
format() directly. And since it's doing that without having to look up<br>
.format on the string, we'd get some performance back that str.format()<br>
currently suffers from.<br>
<br>
Nothing is really lost by not merging the adjacent strings, since the<br>
f-strings by definition are replaced by function calls. Maybe the<br>
optimizer could figure out that 'foo ' + 'b:' could be merged in to 'foo<br>
b:'. Or maybe the user should refactor the strings if it's that important.<br>
<br>
I'm out of the office all day and won't be able to respond to any follow<br>
ups until later. But that's good, since I'll be forced to think before<br>
typing!<br>
<br>
Eric.<br>
<br>
[1] Which makes me think of the crazy idea of passing in unevaluated<br>
f-strings in to another function to be evaluated in their context. But<br>
the code injection opportunities with doing this with arbitrary<br>
user-specified strings are just too scary to think about. At least with<br>
str.format() you're limited in to what the expressions can do. Basically<br>
indexing and attribute access. No function calls: '{.exit()}'.format(sys) !<br>
<br>
</blockquote></div><br><br clear="all"><br>-- <br><div class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div>