[Python-ideas] Let’s make escaping in f-literals impossible
Steven D'Aprano
steve at pearwood.info
Tue Aug 30 12:34:39 EDT 2016
On Tue, Aug 30, 2016 at 11:43:03PM +1000, Chris Angelico wrote:
> On Tue, Aug 30, 2016 at 10:56 PM, Philipp A. <flying-sheep at web.de> wrote:
> > My issue is just that it’s as much of a string as a call of a (string
> > returning) function/method or an expression concatenating strings:
> >
> > ''.join(things) # would you call this a string?
> > '{!r}'.format(x) # or this? it’s basically the same as this “f-string”:
> > f'{x!r}'
> > 'start' + 'end' # or this? it’s a concatenation of two strings, just like
> > f'start{ "end" }'
>
> Yes, an f-string is really a form of expression, not a literal. But
> prior art has generally been to have similar constructs referred to as
> "interpolated strings" or similar terms:
>
> https://en.wikipedia.org/wiki/String_interpolation
*shrug* A misleading name is misleading no matter how many people use
it. If <insert the name of a language you dislike here> started calling
function calls:
func(arg, x, y, z+1)
"s-strings" for "source code strings", because you write them as source
code, and changed the syntax to
func"arg, x, y, z+1"
we'd all recognise what a mistake it is to call this a string, string
delimiters or not. The *result* of calling it may be a string, but the
expression itself is a kind of function call.
[nasty thought]
Why don't we allow func"*args" as syntactic sugar for str(func(*args))?
[/remove tongue from cheek]
> Plenty of languages have some such feature, and it's usually
> considered a type of string.
The result is a type of string. The expression is not.
> Notice the close parallels between actual
> string literals used as format strings ("I have %d apples" % apples)
> and f-strings (f"I have {apples} apples"),
That's a misleading comparison. The *template string* is "I have %d
apples" and that is just a string. The *format operator* is % and the
formatting operation or expression is the entire expression.
Since f-strings can contain arbitrary expressions, the analogy is not
with the template string, but a function (method or operator) call:
f"I have {fruit - bananas - oranges} apples"
is not equivalent to "I have {} apples", but to
"I have {} apples".format(fruit - bananas - oranges)
which is clearly a method call that merely returns a string, not a
string itself.
Consequently, there's no way to delay evaluation of such an f-string,
any more than you can delay evaluation of the expression[1]:
func(fruit, 2*bananas, 3/oranges)
You can't generate a template, and pass it to different environments to
be formatted. If you need to evaluate f"I have {apples} apples" in six
different contexts, you have to repeat yourself: it is equivalent to a
function call, complete with implicit arguments, not a function object,
and certainly not equivalent to a template string.
> and how this same parallel
> can be seen in many other languages. Yes, it may be a join expression
> to the compiler, but it's a string to the programmer.
Only if the programmer is fooled by the mere use of string delimiters.
It really isn't a string. It is executable code that returns a string.
It is basically a distant cousin to eval(), in disguise.
I really wish we had a better name for these things than f-strings :-(
[1] Tricks with eval() excluded.
--
Steve
More information about the Python-ideas
mailing list