-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add = to f-strings for easier debugging. #80998
Comments
This is an alternative proposal to bpo-36774. We (Eric V. Smith and Larry Hastings) propose a minor language Python programmers often use "printf-style" debugging. In the f-strings make this slightly nicer to type: But you still have to repeat yourself: you have to write f-strings are uniquely able to help with this. Their implementation The initial idea was to use an f-string "conversion", which we We considered other spellings: And then! On Saturday, the best spelling revealed itself! Behold With this spelling change, we've also refined the semantics. By default, f-strings use format() (technically they call Second, this is now composable with conversions. So you can use Relatedly, we've added a new conversion: "!f" means "use format()", Finally, and this is the best part: what if you want whitespace around What's particularly elegant is that we simply preserve all the Please vote! Eric and /arry |
I'll assume you can resolve any weird corner cases, in which case +1 |
+1 from me (as a big fan of print-debugging). |
I like this! Except that I think that !f is not needed. You can use repr by default only when no format spec is specified, and add explicit !r if you want to use repr with the format spec. If you want to format the value without repr and the format spec -- specify the empty format spec: f"{foo=:}". |
I had this working in bpo-36774, but it seems like a little too much magic. It also prevents you from formatting the result of the repr, which works in f-strings without the =. Say you wanted a fixed width output. You need to apply a format to the value of the repr: >>> nums = [1/3, 1.0, 10.0, math.pi]
>>> for n in nums:
... print(f'*{n=}*')
...
*n=0.3333333333333333*
*n=1.0*
*n=10.0*
*n=3.141592653589793*
>>> for n in nums:
... print(f'*{n=:30}*')
...
*n=0.3333333333333333 *
*n=1.0 *
*n=10.0 *
*n=3.141592653589793 * If the presence of a format spec meant automatically apply the format to the value being printed, this wouldn't be possible. |
You can use f'*{n=!r:30}*' if you want to format the result of the repr. In you example the format spec is applied to both the value and the literal representation of the expression. Is it an error? I do not think this is an expected behavior. If you want to apply it to both the literal expression and its value you can use the nested f-string: f"*{f'{n=}':30}*". There is not too much more magic here: if both converter and format specifier are omitted use !r because it is a common special case. I think it is better than the other difference in the default converter used for debugging and normal formatting. |
No, you're misreading it. I admit that my example wasn't great. Try this one: >>> for n in nums:
... print(f'*{n=:+<30}*')
...
*n=0.3333333333333333++++++++++++*
*n=1.0+++++++++++++++++++++++++++*
*n=10.0++++++++++++++++++++++++++*
*n=3.141592653589793+++++++++++++*
Correct. There's a similar discussion in bpo-36774. |
Actually that's how !d worked. We changed the behavior because it was too "magical". We need to keep the f-strings format spec simple so it was easier to remember. I for one already have difficulty remembering how f-string formatting works, I don't want to make add even more complications. In the current proposal, the special syntax must be specified in a particular order, and the order is easy to remember because information always flows from left-to-right. The "=" must come before the "!" and/or the ":", and the "!" must come before the ":". Like so: f'{foo Modification information strictly flows from left to right:
If we made the default conversion function when using = dependent on the presence or absence of the format spec, now we have information flowing to the left, all the way from the end to the beginning. Eric and I agree: this is too magical and too hard to remember. We want to keep it simple. (True story: Eric had the !d implementation already done and ready for checkin. When he changed it to this = syntax he actually mostly *threw out* code, because this way is simpler and more regular. Hopefully you're thinking "well THAT sounds nice!"--we agree.) |
After discussing this with Guido and Larry, we're going to go with the "implicit format mode", as outlined by Serhiy, and drop the !f feature. So the rules are: I think the 95% case will be {x=}, the 99%+ case will be {x=:2f} case. So I'm happy with this outcome. All functionality you had available with !f is still available, but with slightly different spellings. The most common cases now have the shortest spellings. |
The most recent version of the PR 0ec4dae has the behavior without !f and auto-selecting what used to be !f. It's ready for a final review before I commit it. |
Commit 9a4135e introduced a reference leak: https://buildbot.python.org/all/#/builders/80/builds/587/steps/3/logs/stdio Bisect results for test_future: 0:00:00 load avg: 10.04 [1/1] test_future == Tests result: FAILURE == 1 test failed: Total duration: 300 ms
:040000 040000 303c86dc65bb09cade6b8f2a0fa3f97715f1793b 7ddfc1c6c5f86bf6d0a38a64ff1415c7ca55a5fe M Doc |
Opened PR13249 to fix the leak |
I'm not quite sure I completely understand how this is implemented and all the possibilities; – so I would appreciate reviews on the issue (and patch) to handle this in ast-unparse. See https://bugs.python.org/issue37003 Thanks, |
The reason the main CI did not catch this is that test_tools is only executed on a (random) subset of all the files if I remember correctly because when executed on all files it massively increases the time of the CI. |
Anecdotally, this happened as well when in the implementation of PEP-572 |
Don't know how good this implemented feature is but , one of the mess is the getting item from dict in python since you have to put a [] and then "" in f strings. d = {"a":90, "b":67}
print(f"a is {d['a']} and b is {d['b']}") Any intention to improve this in future? |
@Teut2711 : I'm not sure what you're proposing. If you have a concrete suggestion, please discuss it at https://discuss.python.org/c/ideas/6 |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: