I am against it, because it allows arbitrary Python expressions inside format strings. It's too complicated and lets user have two different ways of doing things (not Pythonic) - one to calculate expression inside string and the other to calculate it outside (which should IMHO be preferred). This should maybe go to the standard library, but please not into the language.<p>I think a better approach would be to just add special formatter operators (if they aren't already there) that would just call str() or repr() or ascii() to whatever is presented to them (and maybe take some optional arguments such as length or padding).
<p><pre><code> There should be one-- and preferably only one --obvious way to do it.
</code></pre>
This would be the 4th way of formatting strings in Python.
I would be very happy to see <i>some version</i> of this accepted.<p>When it comes to native String interpolation Groovy has it, Scala has it, ES6 has it apparently; to a more limited extent Bash, PHP, Perl have it too of course.<p>I can't help feeling that other devs are now coming to Python expecting this kind of feature, and are disappointed to find three (harder, often less readable) ways to do it instead. Got to keep up with the Joneses, etc...
Nonononono. Python does not need more string literal specifiers. For a language that avoid symbols and sigils like the plague, it already has an absurd amount of string literal syntax.<p>Why not make a strfmt library on pypi that provides a single <i>fmt(s, args, kwargs)</i> function and let people call that? Why the obsession with more builtins?
The first thing I thought of when I looked at the PEP was, "this is like a string version of register_globals=on".<p>A string literal whose value automatically changes with the code surrounding it sounds like a really bad idea.<p>I also noticed that the PEP uses str.format method as a strawman, ignoring the fact that % string interpolation is very popular and does not need replacing, which is at the core of this problem in the first place; Someone keeps trying to replace something that does not need replacing.<p>Furthermore, I can't help but think that this would eventually become a complete literal string DSL (if not one already) inside of Python.<p>I hope this PEP does not get accepted.
This is a massive improvement. I currently use .format(), sometimes with <i></i>locals(), but f-strings would improve this massively.<p>Now if only they didn't require Python 3, so I could use them on the production systems I'm working on...
I am having some problems trying to understand the implementation. What would the AST from evaluating "f'{a+1}'" look like? Will there be a special AST node for f-strings, or will it be pre-structured into the AST?<p>If it's a special node, is it the responsibility of the byte code generator to parse the string? My belief is that it's part of the parser's job, so the AST will never contain an f-string.<p>What does a syntax error report look like? Or traceback? Will it be able to narrow down the part of the string which causes a problem?<p>Can f-strings include f-strings, like:<p><pre><code> f"{a + (f' and {b+1}')}"
</code></pre>
I assume the answer is 'yes, and you shouldn't do that', which I can accept.<p>Support for arbitrary expressions inside of an f-string means that the following is allowed,<p><pre><code> def f(a, b):
return f"{yield a} = {b}"
print(f(1, 2))
</code></pre>
and will work, and will print <i>something</i>, but it won't be "1 = 2". Nor will any but heavy-weight analysis tools be able to figure out that this 'f' is a generator.<p>I am less happy accepting that a magic string can turn a function into a generator. Take for example this code from around line 438 of <a href="https://searchcode.com/codesearch/view/18830026/" rel="nofollow">https://searchcode.com/codesearch/view/18830026/</a> :<p><pre><code> if attr=='yields' :
yield_unit = self._grab_attr_(obj,'yield_unit')
if yield_unit:
ret = '%s %s'%(ret,yield_unit) # FIXME: i18n?
return ret
</code></pre>
The penultimate line could be rewritten, validly, as:<p><pre><code> ret = f'{ret} {yield_unit}' # FIXME: i18n?
</code></pre>
The introduction of a typo, from 'yield_unit' to 'yield unit', would drastically change the function, and be very hard to spot.<p><pre><code> ret = f'{ret} {yield unit}' # FIXME: i18n?
</code></pre>
Yes, Don't Do That, but we know that people use things like syntax highlighters to help understand the code and identify mistakes like this.<p>EDIT: the PEP says that the expression are "parsed with the equivalent of ast.parse(expression, '<fstring>', 'eval')". That means that 'yield' is not allowed.
For those that want something close today, there's <a href="https://pypi.python.org/pypi/say" rel="nofollow">https://pypi.python.org/pypi/say</a><p><pre><code> fmt("Hello, {name}! You have {len(msgs)} waiting.")
</code></pre>
Interpolates local variables and expressions. It uses the format method, and has all of format's output formatting.
There's an interesting competing PEP which allows for the way in which the expressions are interpolated into the string to be customized: <a href="https://www.python.org/dev/peps/pep-0501/" rel="nofollow">https://www.python.org/dev/peps/pep-0501/</a>
I hope this gets implemented. A year ago or so we had several customers wanting to custom format output filenames and directories in a desktop application and we settled for something which is almost exactly this, so the {identifier:format spec} idea, and ever since implementing it I wish any language had it as we found it really convenient and having no apparant disadvantages in comparision with printf-%-style in C or Python/streams in C++/{}-style in C#/Python
<i>However, str.format() is not without its issues. Chief among them is its verbosity. For example, the text 'value' is repeated here:</i><p><pre><code> >>> value = 4 * 20
>>> 'The value is {value}.'.format(value=value)
'The value is 80.'
</code></pre>
<i>Even in its simplest form, there is a bit of boilerplate, and the value that's inserted into the placeholder is sometimes far removed from where the placeholder is situated:</i><p><pre><code> >>> 'The value is {}.'.format(value)
'The value is 80.'
</code></pre>
<i>With an f-string, this becomes:</i><p><pre><code> >>> f'The value is {value}.'
'The value is 80.'
</code></pre>
Yeah I've had this thought before.
You can even hack it into a string class if you don't mind using even more scary hacks like monkey patching built in classes.<p><pre><code> def I(s):
import inspect
frame = inspect.currentframe()
caller_locals = frame.f_back.f_locals
return s.format(**caller_locals)
def main():
a = 12
b = 10
print I('A is {a} and B is {b}')
if __name__ == '__main__':
main()</code></pre>
In TXR Lisp, from system prompt:<p><pre><code> # simple quasiliteral, denoted by backticks
$ txr -p '(let ((x "Bob")) `Hello, @{x -10}`)'
"Hello, Bob"
# word-quasiliteral (breaks into list on spaces)
# denoted by hash-backtick:
$ txr -p '#`@(+ 2 2) @(+ 1 2) a b c`'
("4" "3" "a" "b" "c")
# op-argument references in quasiliteral
# ret produces a function whose arguments depend
# on the uses of @1, @2. ... and @rest in the
# expression. The value of the expression is returned.
# These references can emanate from a quasistring:
$ txr -p "(mapcar (ret \`@1--@2--@rest\`) '(1 2 3) '(a b c) '(x y z)))"
("1--a--x" "2--b--y" "3--c--z")
# Very basic indexing, slicing and field adjustment:
$ txr -p '`foo @{(list 1 2 3) [0]} bar`'
"foo 1 bar"
$ txr -p '`foo @{(list 1 2 3) [2]} bar`'
"foo 3 bar"
$ txr -p '`foo @{(list 1 2 3) [1..:]} bar`'
"foo 2 3 bar"
$ txr -p '`foo @{(list 1 2 3) [1..:] 20} bar`'
"foo 2 3 bar"
$ txr -p '`foo @{(list 1 2 3) [1..:] -20} bar`'
"foo 2 3 bar"
</code></pre>
Interpolation into quasi-literals is very useful and expressive; I use it all the time. Doing trivial things should look trivial in the code.<p>Oh, right: referencing splices and unquotes is possible from inside a quasistring:<p><pre><code> $ txr -p '(let ((a 42) (b (range 1 5)))
^(list `hey @,a @(list ,*b)`))'
(list (sys:quasi "hey "
@42 " " @(list 1 2 3 4 5)))
$ txr -p '(eval (let ((a 42) (b (range 1 5)))
^(list `hey @,a @(list ,*b)`)))'
("hey 42 1 2 3 4 5")
</code></pre>
Safe to say, that one's not coming to a Python near you.
This looks like template strings in ES6 [1], which is really well done ! I look forward to using f-strings<p>[1]: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings" rel="nofollow">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...</a>
This is a very handy feature of PHP and would be useful in Python. I think readability will be solved by syntax highlighting: expressions in an f-string would be highlighted like normal expressions, rather than like string content. This is what is already done for PHP.
I'm really happy to see this. I know it's petty, but this was the biggest reason I decided to focus on learning the ins and outs of Ruby instead of Python.
I understand the need for expressions-in-literal.<p>I really don't understand why the unnecessary extra "!rsa" modifiers are a good thing though.