People are wtf-ing a bit about the positional-only parameters, but I view that as just a consistency change. It's a way to write in pure Python something that was previously only possible to say using the C api.
People are wtf-ing a bit about the positional-only parameters, but I view that as just a consistency change. It's a way to write in pure Python something that was previously only possible to say using the C api.
Digression on the old way's shortcomings: Probably the most annoying thing about the old "format" syntax was for writing error messages with parameters dynamically formatted in. I've written ugly string literals for verbose, helpful error messages with the old syntax, and it was truly awful. The long length of calls to "format" is what screws up your indentation, which then screws up the literals (or forces you to spread them over 3x as many lines as you would otherwise). It was so bad that the format operator was more readable. If `str.dedent` was a thing it would be less annoying thanks to multi-line strings, but even that is just a kludge. A big part of the issue is whitespace/string concatenation, which, I know, can be fixed with an autoformatter [0]. Autoformatters are great for munging literals (and diff reduction/style enforcement), sure, but if you have to mung literals tens of times in a reasonably-written module, there's something very wrong with the feature that's forcing that behavior. So, again: f-strings have saved me a ton of tedium.
print('I do not get executed :)')
f'{!}'
File "stefco.py", line 2
f'{!}'
^
SyntaxError: f-string: empty expression not allowed
This has the pleasing characteristic of eliminating an entire class of bug. :)Have you looked at textwrap.dedent?
raise ValueError("File exists, not uploading: "
f"{filename} -> {bucket}, {key}")
...which is short enough that it's readable, and it's clear where exactly each variable is going. It's the single obvious solution, so much so that I don't spend a second thinking about it (very Pythonic!). Compare it to using `str.format` with the same continued indentation: raise ValueError(("File exists, not uploading: {filename} -> "
"{bucket}, {key}").format(filename=filename,
bucket=bucket,
key=key))
Even this minimal example looks terrible! Remember that a lot of exceptions are raised within multiply-nested blocks, and then format pushes things farther to the right (while also ruining your automated string-literal concatenation, hence the extra parentheses), leaving very little room for the format arguments. You can use a more self-consistent and readable indentation strategy: raise ValueError(
(
"File exists, not uploading: {filename} -> "
"{bucket}, {key}"
).format(filename, bucket, key)
)
This is unquestionably more pleasant to read than the former, but it's 3 times longer than the simple f-string solution, and I would argue it is not any more readable than the f-string for this simple example. My point with having a `str.wrap` builtin is that at least you could use the docstring convention of terminating multi-line strings on a newline, which would get rid of the string concatenation issues while leaving you a consistent (albeit diminished by the "wrap" call) amount of rightward room for the `format` args: raise ValueError("""File exists, not uploading: {filename} ->
{bucket}, {key}
""".dedent().format(filename=filename,
bucket=bucket, key=key))
Maybe a little bit better than the first one, especially if you're writing a longer docstring and don't want to think about string concatenation. But still a kludge. You can use positional formatting to shorten things up, but the fundamental weakness of `str.format` remains. str_fmt = "File exists, not uploading: {filename} -> {bucket}, {key}"
fmt_vals = dict(filename=filename, bucket=bucket, key=key)
raise ValueError(str_fmt.dedent().format(**fmt_vals)) raise ValueError(“File exists, not uploading: {filename} -> {bucket}, {key}”.format(**locals())) raise ValueError(("File exists, not uploading: {filename} -> "
"{bucket}, {key}").format(filename=filename, bucket=bucket, key=key))That post makes a few things very clear:
* The argument over the feature did not establish an explicit measure of efficacy for the feature. The discussion struggled to even find relevant non-Toy code examples.
* The communication over the feature was almost entirely over email, even when it got extremely contentious. There was later some face-to-face talk at the summit.
* Guido stepped down.
But just because the feature shipped and design-by-committee is upon us doesn't mean we need to accept the outcome. Why couldn't there have been a more evolutionary path for this feature? For example, there is surely a way to write a prototype library to accomplish the same effect with slightly different syntax. (How about a single function `walrus(a, b)` that does what `:=` does?). Then let real user adoption drive the change. Maybe somebody will discover case statements from scala and want that instead.
I hope the committee models some amount of their work after WG21. C++ hasn't evolved so effectively because some people were magic visionaries. For the past decade, C++ has mostly ridden on the proven success of boost. And skipped a lot of the parts of boost that suck.
I've used assignment expressions in other languages too! Python's version doesn't suffer from the JavaScript problem whereby equality and assignment are just a typo apart in, eg., the condition of your while loop. Nonetheless, I find that it ranges from marginally beneficial to marginally confusing in practice.
Ergonomically, I see little benefit for the added complexity.
I don't want a type error for the most clear use case, in the same way I don't want one for print, because if I wanted a behaviour other than the basic string representation then I would still need to call something differently anyway.
Given that explicit control of the __str__ method is also baked into the language it's also very clear what to expect.
I like type errors when handling something like '1' + 1 because the JavaScript alternative is surprising and hides bugs. No surprises that a string formatter would coerce to string for me automatically (although I get that's maybe just personal feeling).
I love the f strings, they have made my codebase cleaner and clearer. Definitely a pythonic win.
Special cases aren't special enough to break the rules, Although practicality beats purity.
But there's a long standing trend of adding more and more of these small features to what was quite a clean and small language. It's becoming more complicated, backwards compatibility suffers, the likelyhood your coworker uses some construct that you never use increases, there is more to know about Python.
Like f-strings, they are neat I guess. But we already had both % and .format(). Python is becoming messy.
I doubt this is worth that.
I need to do 2 changes every time I change a format string - I need to remove the symbol representing it's placement and then I need to remove the argument passed to .format.
Also old formatting does not easily support arbitrary expressions in the placements, thus in order to get those you need to change the arguments passed to the .format.
f-strings get rid of those issues altogether. What you're showing is whatever you have in the brackets - 0 indirection and thus less margin for (unnecessary) errors.
That said, I also struggle to understand how you’d claim parent clearly not using Python enough, when your description of str.format shows a lack of understanding to it yourself. One of the advantages of str.format over %-formatting is exactly that you do not need to modify the arguments passed to str.format when removing components from the source string:
>>> '{0} {1} {2}'.format('a', 'b', 'c')
'a b c'
>>> '{0} {2}'.format('a', 'b', 'c')
'a c'
Or preferably (using keyword arguments instead of positional): >>> '{x} {y} {z}'.format(x='a', y='b', z='c')
'a b c'
>>> '{x} {z}'.format(x='a', y='b', z='c')
'a c'
But again, this doesn’t matter to parent’s argument. Nobody is arguing with you that f-string is better than alternatives for what it can do; we are trying to tell you that there are things it can’t do, and you did not get it.It's not the string that most of the developers care about, it's the presence of the arguments to that string. The issue they are solving is "I would like to see A, B and C", rather than the issue of "I have provided A, B and C - would you please hide B from the view".
>> But again, this doesn’t matter to parent’s argument. Nobody is arguing with you that f-string is better than alternatives for what it can do; we are trying to tell you that there are things it can’t do, and you did not get it.
Please elaborate on what the f-string can't do? You have not provided the answer in your post. In my opinion, the only issue f-strings haven't solved is capturing the arguments in lambdas (before interplation) instead of their direct values. You, on the other hand - do not provide a clear explanation.
"The straw that broke the camel’s back was a very contentious Python enhancement proposal, where after I had accepted it, people went to social media like Twitter and said things that really hurt me personally. And some of the people who said hurtful things were actually core Python developers, so I felt that I didn’t quite have the trust of the Python core developer team anymore."
Source: https://www.infoworld.com/article/3292936/guido-van-rossum-r...
Note that Guido also was in support of the walrus operator, it's not like he stepped down because he disagreed with it.
We've spent decades debating on the merits of spaces vs tabs, and Vim vs Emacs, and a ton of other completely pointless stuff.
What you're hoping is just a pipe dream, people will get invested in the most petty and asinine stuff out there, and take it as a personal insult if you disagree.
[1] https://www.python.org/dev/peps/pep-0572/#alternative-spelli...
Disagree. In cases where it's useful it can make the code much clearer. Just yesterday I wrote code of the form:
foos = []
foo = func(a,b,c,d)
while foo:
foos.append(foo)
foo = func(a,b,c,d)
With the walrus operator, that would just be: foos = []
while foo := func(a,b,c,d):
foos.append(foo)
Further, I had to pull out 'func' into a function in the first place so I wouldn't have something complicated repeated twice, so it would remove the need for that function as well.Also, it's times like these I'm really glad docker exists. Trying that out before docker would have been a way bigger drama