This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: f-strings do not support top-level :=
Type: Stage: resolved
Components: Documentation Versions: Python 3.8
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: SilentGhost, barry, emilyemorehouse, eric.smith, gvanrossum, larry, loganasherjones, lukasz.langa, scoder, serhiy.storchaka, xtreak
Priority: normal Keywords: easy, patch

Created on 2019-05-05 01:23 by eric.smith, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 13107 merged loganasherjones, 2019-05-06 14:05
Messages (22)
msg341413 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-05-05 01:23
The walrus operator breaks f-strings, because the f-string scanner sees the colon as the end of the expression.

>>> x = '10'
>>> f'{x:=10}'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: '=' alignment not allowed in string format specifier

This becomes: format(x, '=10'), which is an error if x is a string.
msg341423 - (view) Author: SilentGhost (SilentGhost) * (Python triager) Date: 2019-05-05 07:13
This doesn't seem at all related to walrus operator, I can reproduce this error on 3.6.7 and 3.7.3, given that format call returns exactly the same error, it seems like '=' is simply not a valid alignment for strings.

I'm not saying that walrus operator did not introduce any errors, but those could be perhaps best tested using the following code:

f'{x:=^10}'
msg341425 - (view) Author: Larry Hastings (larry) * (Python committer) Date: 2019-05-05 10:41
The point is that := is valid expression syntax in Python 3.8, but you can't use it in an f-string.  The fact that the error is the same in 3.6 and 3.7 is irrelevant because := was not valid syntax in those versions.
msg341426 - (view) Author: SilentGhost (SilentGhost) * (Python triager) Date: 2019-05-05 11:04
> The point is that := is valid expression syntax in Python 3.8, but you can't use it in an f-string.

Good? Allowing walrus operator in the f-strings will just lead to the debugging hell.
msg341428 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-05-05 11:17
f-strings are not going to take a position on what a "good" expression is, and what is and isn't allowed. If it's a Python expression that could possibly be parsed in the f-string context, f-strings will allow it. This is clearly a bug in 3.8. I'll have a PR today or during the sprints.
msg341429 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-05-05 11:25
You can use it in parenthesis:

>>> f'{(x:=10)}'
'10'

It should be explicitly documented, that what looks like the assignment operator is not always the assignment operator in f-strings.

>>> x = 10
>>> f'{x:=10}'
'        10'
msg341432 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-05-05 11:55
Correct about the parens. I'm just going to fix it a the top level, without parens. There's no reason it shouldn't work, the fact that it doesn't work now is just an accident of implementation.

I'll fix it by adding a special test, the same way that != has a special test.

For those who say it shouldn't be allowed at the top level anyway, but should be allowed in parens: if we decide that (which I disagree with), then it should not be disallowed because of an accidental interaction with format specs. It should be explicitly checked for and disallowed. Again, I am not planning on making that change. I'm just going to allow it.
msg341433 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-05-05 12:08
Allowing it at the top level is a breaking change. It should not be done without deprecation. And I think that it is better to use parenthesis around the assignment operator (or better do not use it in f-strings at all) that deprecate the "=" alignment.
msg341434 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2019-05-05 12:20
There was a note on PEP 572 (https://www.python.org/dev/peps/pep-0572/#exceptional-cases) to prohibit as a top level expression and a discussion on the issue also didn't agree with it https://bugs.python.org/issue35224#msg339098 . It might cause confusion to users due to this difference inside and outside of f-strings.
msg341435 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-05-05 12:44
Note that Guido prefers to use parentheses around the assignment operator even if the grammar does nor require this. He used this style in What's New.
msg341443 - (view) Author: Larry Hastings (larry) * (Python committer) Date: 2019-05-05 13:19
I'm not sure why Guido's preferences would be relevant.  f-strings support expressions, := is a valid expression, f-strings therefore must support it. 
 f-strings expressions are not top-level statements and therefore will not require parentheses around :=.

There appears to be some confusion around f-strings' use of : to delimit a "format specification".  Supporting := won't break format specifications, although it will require some intelligence--if you see a :, you must examine the next character to know whether it's := or a format specification.  It is not a breaking change.
msg341451 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-05-05 14:32
The fact that adding := support could break existing working code does give me pause to make any change here, and does suggest that a deprecation period would be needed in order to modify the f-string expression scanning behavior.

One concern I have is that if something akin to PEP 536 is used to implement f-strings, then it would require some work (but not be impossible) to avoid allowing :=.

In 3.8, := is prohibited in "expression as a statement" mode, but that's not the mode that f-strings expressions operate in: they're just normal expressions, and I would normally just expect := to work. But the backward compatibility break here is the reason to possibly disallow supporting :=, not that := should just never work in f-strings without parens.
msg341454 - (view) Author: Emily Morehouse (emilyemorehouse) * (Python committer) Date: 2019-05-05 15:42
My initial reaction is that named expressions should not be valid in f-strings and should instead raise an exception, the same way that using `a := 10` does.

>>> a := 10
  File "<stdin>", line 1
    a := 10
      ^
SyntaxError: invalid syntax

It could be expected that named expressions could be used in f-strings in the same way as, say, list comprehensions or when used in parenthesis. One of the tricky things about named expressions is that the scope of the variable being assigned to gets "elevated" to the enclosing scope (this is a slightly simplified explanation but applies for most cases).

Since f-strings are executed when defined and not where they are used, this could lead to confusing behavior. Is it available only when defined? Would users expect a variable to be available again when the f-string if it were saved to a variable? Would we modify the expected behavior of named expressions to contain scope to only the f-string? I'm not sure that any of these are particularly clear in behavior or in the definitions laid out in PEP 572.
msg341458 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-05-05 16:51
f-strings are defined and used at the same place, as any other expression. You can not save an f-string to a variable, as you can not save a multiplication. But you can save a string which is a result of the f-string evaluation.

Perhaps you were fooled by the name of f-strings. It looks as a special kind of strings, but actually it is a kind of expressions, like addition or multiplication.
msg341461 - (view) Author: Emily Morehouse (emilyemorehouse) * (Python committer) Date: 2019-05-05 17:26
Ah yes, that's what I meant. I was thinking about the confusion between f-strings (evaluated immediately and stored as a string) vs other versions of string formatting which are evaluated when used. I've seen the mix of the two confuse people when evaluating performance. I don't think this is particularly relevant to this issue though, so we can ignore it :)
msg341464 - (view) Author: Stefan Behnel (scoder) * (Python committer) Date: 2019-05-05 17:56
FWIW, I think it's equally reasonable to allow assignment expressions directly in f-strings, as it is to require parentheses with a reference to the invalidity of top-level expressions.

That makes me lean towards adding a parse-time error message that suggests the right way to do it, and leave it out as a feature for now, because it risks conflicting with ":" as format separator. We do not know yet if we will really need this feature. It's easier to add the feature later, than to remove it again in case we find that it gets in the way more than it helps.
msg341466 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-05-05 18:30
Because of the backward compatibility issues, I'm not going to change the f-string parser for this. We'll just need to document the requirements for using parens if you want to use :=. This is similar to the existing documentation about lambdas and f-strings in https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals

Patches welcome!

To be clear: like lambdas, this is just limitation of embedding expressions inside strings, and it's also a limitation because format specs can start with equal signs. It's not a restriction because I think f-strings shouldn't contain "top-level" := expressions.
msg341469 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-05-05 18:42
And I think that PEP 572 should be updated too. This is a corner case that was omitted at initial consideration of the PEP.
msg341471 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2019-05-05 19:10
I agree with Serhiy about the need to update PEP 572 to mention this.
msg341501 - (view) Author: Logan Jones (loganasherjones) * Date: 2019-05-06 13:52
I'm going to try to tackle this. I'm not exactly sure how to go about updating the PEP, but the docs should have a PR in the next 15 minutes or so.
msg341557 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2019-05-06 16:32
New changeset ae2c32f32b61f3b141ba4b0b1ad71781d2f9a1a1 by Guido van Rossum (Logan Jones) in branch 'master':
bpo-36798: Updating f-string docs for := use case (GH-13107)
https://github.com/python/cpython/commit/ae2c32f32b61f3b141ba4b0b1ad71781d2f9a1a1
msg341558 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2019-05-06 16:33
PEP and docs have been amended.
History
Date User Action Args
2022-04-11 14:59:14adminsetgithub: 80979
2019-05-06 16:33:17gvanrossumsetstatus: open -> closed
resolution: fixed
messages: + msg341558

stage: patch review -> resolved
2019-05-06 16:32:48gvanrossumsetnosy: + gvanrossum
messages: + msg341557
2019-05-06 14:05:51loganasherjonessetkeywords: + patch
stage: needs patch -> patch review
pull_requests: + pull_request13021
2019-05-06 13:52:28loganasherjonessetnosy: + loganasherjones
messages: + msg341501
2019-05-05 19:10:04eric.smithsetkeywords: + easy

messages: + msg341471
stage: needs patch
2019-05-05 18:42:05serhiy.storchakasetmessages: + msg341469
2019-05-05 18:30:18eric.smithsetpriority: release blocker -> normal
assignee: eric.smith ->
messages: + msg341466

components: + Documentation, - Interpreter Core
2019-05-05 17:56:28scodersetnosy: + scoder
messages: + msg341464
2019-05-05 17:26:54emilyemorehousesetmessages: + msg341461
2019-05-05 16:51:18serhiy.storchakasetmessages: + msg341458
2019-05-05 15:42:39emilyemorehousesetmessages: + msg341454
2019-05-05 14:55:45eric.smithsettitle: := breaks f-strings -> f-strings do not support top-level :=
2019-05-05 14:32:05eric.smithsetmessages: + msg341451
2019-05-05 13:19:17larrysetmessages: + msg341443
2019-05-05 12:44:44serhiy.storchakasetmessages: + msg341435
2019-05-05 12:20:38xtreaksetnosy: + xtreak
messages: + msg341434
2019-05-05 12:08:53serhiy.storchakasetmessages: + msg341433
2019-05-05 11:55:09eric.smithsetmessages: + msg341432
2019-05-05 11:25:07serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg341429
2019-05-05 11:17:58eric.smithsetmessages: + msg341428
2019-05-05 11:04:19SilentGhostsetmessages: + msg341426
2019-05-05 10:41:49larrysetmessages: + msg341425
2019-05-05 07:13:11SilentGhostsetnosy: + SilentGhost
messages: + msg341423
2019-05-05 03:20:50barrysetnosy: + barry
2019-05-05 01:36:50xtreaksetnosy: + emilyemorehouse
2019-05-05 01:23:34eric.smithcreate