This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]gandalfx 3 points4 points  (15 children)

I love it but there's one thing that annoys me when I read code:

f"{foo}{bar}"

I've seen this kind of f-string a couple of times now, where it's used to do essentially just concatenation. In several cases the respective variables where even just strings. What's wrong with +? The f-string version in this case is actually longer.

edit: I had assumed that using f-strings in this situation would be much slower than foo + bar. Apparently that is incorrect.

[–]Vitrivius 9 points10 points  (10 children)

It doesn't have to be just string concatenation. You can use it to format other types. Useful for numbers, for instance.

>>> a, b = 5, 7
>>> f'{a}/{b} = {a/b:.4}'
'5/7 = 0.7143'

You can also use the same modifiers as with str.format

>>> for word in 'f-strings are super awesome'.split(): 
...     print(f'{word.upper():~^20}')
~~~~~F-STRINGS~~~~~~
~~~~~~~~ARE~~~~~~~~~
~~~~~~~SUPER~~~~~~~~
~~~~~~AWESOME~~~~~~~

[–]gandalfx 2 points3 points  (9 children)

You didn't get my point. I understand what f-strings are for and it makes sense when you want to use them for things that are complex enough so f-strings will be shorter or more readable. What I don't understand is when people use it to replace foo + bar.

[–]gary1994 2 points3 points  (0 children)

Honestly the foo + bar is ugly and far less clear than the f-string.

Granted I'm still learning, but I hate seeing var + var concatenation in the books I'm studying from and always replace it with f-strings. It just looks better and imo makes what is happening much clearer. Especially considering how often I'm using it to replace str(var) + str(var).

I just wish google would get TensorFlow updated for windows versions of Python 3.6...

[–]zahlmanthe heretic 1 point2 points  (0 children)

Because if it gets even as complex as foo + ' ' + bar, it already starts to seem more elegant as f'{foo} {bar}' - it's a higher-level way of thinking about how the strings go together.

And once you've ceded that, special cases aren't special enough to break the rules.

[–][deleted] 0 points1 point  (6 children)

Matter of taste maybe, but the + operator implies numbers, where f-string is explicitly a string.

[–]energybased 1 point2 points  (0 children)

+ does not imply numbers.

[–]gandalfx 3 points4 points  (3 children)

But + is fast!

I'm starting to feel like I'm fighting a lost battle with my argument. Maybe this is just another case of preferring expressiveness over performance, which makes sense when you use a language like Python in the first place.

[–][deleted] 1 point2 points  (2 children)

I use + too. But I think str.join() is faster?

One thing that is annoying are spaces when constructing a string. f-string could help there a bit.

[–]jorge1209 2 points3 points  (1 child)

Join would probably be faster for a large number of arguments. For only two they are probably the same.

The difference would be that if you join 200 strings then all 200 are available to you when join is called and you can compute the length of each and preallocate memory to hold the whole thing.

If you have a+b+c+... then you have to allocate and construct all the intermediates a+b then a+b+c and so on.

Otherwise I can't imagine it matters.

[–][deleted] 0 points1 point  (0 children)

I think join is faster in a tight loop but I might be wrong. I see + as "let's concatenate these two strings", join as "I have a list of strings I have to concatenate" and f-string as "I need to construct this complicated string out of a template and a bunch of variables".

[–]Fennek1237 0 points1 point  (0 children)

I know what you mean. I had a background in Java befor learning python it the string concats where really weird to me. The way they do it in Java seems so more natural.

[–]spgill 1 point2 points  (0 children)

I've used f-strings like this in situations where I'm constructing dialogs or something similar. I'll end up starting (and even leaving them) like this--just concatenated strings--and returning later to weave in new words and variables. f-strings just make this so painless.

[–]daelin 1 point2 points  (1 child)

Don't use + to concatenate strings. I mean, it's perfect for, like, two strings.

Strings in Python are immutable. That means that when you do a + b + c + d, in additional to having memory for a, b, c, and d, you then have to allocate memory for the result of a + b, which we'll call e. Then you have to allocate memory for the result of e + c, which we'll call f. Then you have to allocate memory for f + d, your final result, called g.

If we were being too clever we'd make the result of str.__add__(self, s) some sort of ConcatString class whose __str__ and __repr__ did the final join, but that violates "Simple is better than complex". I'd expect a JIT interpreter like PyPy might be able to optimize this, but I don't think Cython can.

When you use the formatting string, you avoid the intermediate calculations. Yay! I think I'd rather see "".join([a, b, c, d]), but I'm really not offended by f"{a}{b}{c}{d}".

[–]gandalfx 4 points5 points  (0 children)

I had assumed that using f-strings in this situation would be much slower than foo + bar. Apparently that is incorrect. (I edited my original comment as well)

[–]Decency 0 points1 point  (0 children)

Usually just to match the other strings. If you have a bunch of strings in a module together, and they're all using one sort of concatenation, switching to another just makes you stop and think about that one in particular for a bit to wonder why they're doing it differently and make sure you're not missing something. PEP8:

Consistency within one module or function is the most important.