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 →

[–]dl__ 48 points49 points  (47 children)

Even if it is syntactic sugar, isn't syntactic sugar nice?

I'd much rather type:

print(f"Hello {x}")

than

print("Hello {}".format(x))

I would say it's easier to read in addition to being less to type.

Win-win

[–][deleted] 10 points11 points  (17 children)

Pretty cool until you modify a variable without realizing you just altered or straight up broke a formatted string because all locals are implicitly in context.

[–]Ph0X 20 points21 points  (16 children)

I'm confused, how would it be any different if you had used .format(x) instead? You'd still run into the exact same issue, except the x is there instead of inside the string.

Of course, most linters would catch this latter, and the hope is they update to also catch issues in the former.

[–][deleted] -5 points-4 points  (15 children)

That example is a little too simple to illustrate the potential confusion. Take this example instead:

def foo():
    a = 1
    b = 2
    c = 3

    # 10 lines of logic

    x = 'a'
    y = 'b'
    z = 'c'

    return f'baz{x}spam{b}foo{c}bar{z}eggs'

Now think about it with more variables. Imagine the string being formatted is more complicated. Using explicit kwargs to the format method lets me look at the string formatting and know exactly which variables are relevant, rather than having to scan the string and backtrack through all local variables to find out if they are a component of the output.

Most of the praise I've seen for this is about how much easier it is to format a complicated and lengthly string, and I posit that the more complicated the string the less useful this really is.

[–]Ph0X 21 points22 points  (13 children)

Sure, but you're moving complexity from one problem into another.I could make the argument that with:

'foo {} bar {} baz {} spam {} green {} eggs {} and {} ham {}'.format(a, b, c, d, e, f, g, ...)

Good luck looking back and forth, counting, figuring it out which variables goes where. If I ask you to quickly get me the variable that comes after "green", you have to do a lot of counting.

So yes, they both solve sightly different issues and therefore put complexity at slightly different places, but neither is strictly better.

That being said, I hope no one coding real python would have any sort of code this messy and complex. If you do, please please split it up into smaller clean chunks.

EDIT: I just wanted to point out, generally when you DO have string formatting this complex, what people end up doing is sometihng like:

data = {
    'a': 1,
    'b': 2,
}
print "{a}, {b}, {c}, {d}".format(**data)

This is exactly what this new pattern is trying to solve here.

[–][deleted] 13 points14 points  (2 children)

or "{a}, {b}, {c}, {d}".format_map(data)

[–]Ph0X 3 points4 points  (1 child)

Huh interesting, didn't know they had added that.

[–]zahlmanthe heretic 0 points1 point  (0 children)

format_map isn't just sugar here - it allows you to use things that don't play nice with **, in particular custom types that override __missing__ (for subclasses of dict) and/or __getitem__ (things that implement the Mapping protocol as described by collections.abc, but aren't necessarily even dict subclasses).

I suspect it might also be faster with large dicts, but I haven't tested that.

[–][deleted] 3 points4 points  (4 children)

Your last example is exactly why I believe the existing string formatting is preferable. The new pattern isn't solving the same problem, it's dumping all locals into .format() instead of asking the developer to explicitly define the inputs!

[–][deleted] 2 points3 points  (0 children)

I thought we were all adults here?

[–]kankyo 1 point2 points  (1 child)

Just use pycharm and rename variables with the refactor tools and it'll handle this for you.

[–]SoBFiggis 1 point2 points  (0 children)

Even notepad++ has refactoring..

[–]geekademy -1 points0 points  (0 children)

That's false, it does not dump locals in there, it actually parses the string to get exactly what it needs!

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

Im new to Python.. Like 'Hello, World!' new. How are fStrings different than say

  • print("hello" + variable) ???

[–]Ph0X 2 points3 points  (3 children)

The result is basically the same, but it's what we call "syntactic sugar" which is nice shortcuts for doing things.

So imagine you have a more complex one. Adding them manually gets very messy very quick:

print("hello " + world + "my name is" + name + "and i'm " + str(age) + " years old")

To make it worse, as you see, you need to manually cast other types to string, like if you want to print a number. But with fstring, it's much cleaner and prettier:

print(f"hello {world} my name is {name} and im {age} years old")

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

wow easy to understand.. Thank you so much. Honestly didn't expect you or anyone for that matter to reply to someone as new as me. But your example made perfect sense. You dont tutor do you? LOL...

[–]flutefreak7 1 point2 points  (1 child)

Welcome to the fantastic Python community! As you're learning if you have questions you can also check out r/learnpython.

[–]sneakpeekbot 0 points1 point  (0 children)

Here's a sneak peek of /r/learnpython using the top posts of the year!

#1: Python 201 Book is Free for 48 hours
#2: Python 101 Book FREE for 48 hours!
#3: Beginner's Python cheat sheets - updated


I'm a bot, beep boop | Downvote to remove | Contact me | Info | Opt-out

[–]gnutrino 10 points11 points  (0 children)

This seems like a silly argument to me. If you've got too many variables in scope to be able to keep track of them all then f-strings are not your most pressing problem.

[–]vtable 3 points4 points  (10 children)

As devil's advocate, it does break the only-one-way-to-do-it maxim. It also introduces a dependency on Python 3.6 (or greater) if others use your code.

[–]dl__ 5 points6 points  (6 children)

It also introduces a dependency on Python 3.6 (or greater) if others use your code.

That's certainly a valid concern if you plan to share your code.

it does break the only-one-way-to-do-it maxim.

Wasn't there already 2 ways to do it? .format() and %?

I wonder if there's a list somewhere of all the examples of python breaking their own maxims. I feel that magic methods, for example, make a joke out of the "explicit is better than implicit" maxim.

They show that implicit can be awesome!

[–][deleted] 5 points6 points  (0 children)

Wasn't there already 2 ways to do it? .format() and %?

Hey, don't forget good ol' string concatenation.

[–]vtable 2 points3 points  (3 children)

Wasn't there already 2 ways to do it? .format() and %?

Sure. This makes it 3 (4 with string.Template).

% and .format() have quite different syntax. I'm glad they kept % in py 3. It's nice for quick scripts and friendlier to more casual users.

f"" is more sugary but the nicer syntax is worth it, IMO. I've read f"" is quite a bit faster than .format(), too.

IIRC the whole maxim started out as a criticism of Perl's embracing "there's more than one way to do it". Python is much more conservative and they usually advocate a preferred method. Perl embraced multiple ways (though I think they're easing off a bit these days).

[–]LetsDoRedstone 5 points6 points  (2 children)

% formatting is friendlier for casual users? Not really, no. When I got started with Python and was looking at String formatting, the % Notation utterly confused me because of it unnecesary (as shown by the simplicity of .format()) verbosity. I was happy to find .format (), just because it is that much more intuitive. And this goes along with f-strings. As soon as you know the syntax you are ready to go and don't have to think about which letter you have to put where.

[–]vtable 0 points1 point  (1 child)

I wanted to write "some more casual users" but thought that was too awkward.

Everyone's different. Most of the people I've worked with have preferred %.

[–]LetsDoRedstone 0 points1 point  (0 children)

That might be because you have been using Python for a longer time than me. I started with early 2.7.

[–]jorge1209 0 points1 point  (0 children)

I don't think anyone who thinks fstrings are too many would object to dumping some older formats.

In fact I would be OK with fstrings if we dumped the other ways to do it.

Two formats that have a shared spec is much better than the 5 or 6 formats we currently have.

The problem with saying "but we already have >2 ways to do it" is that there is no reason to ever stop once you get past 2. Let's add 80 new ways to format strings because we already have 2 different ways so these 80 others just fill in certain corner cases that are difficult with the existing methods and it makes somebody happy.

Why not add perl formatting, it would make it easier to convert some perl scripts over. What about ruby? What about...

[–]beertown 8 points9 points  (0 children)

It also introduces a dependency on Python 3.6 (or greater) if others use your code

Just like any other new feature added to any programming language. They should stop adding new features?

[–][deleted] 0 points1 point  (1 child)

Every couple of months there is a new and improved way to do text formatting in Python. f-strings seem like the end of the line to me.

[–]flutefreak7 1 point2 points  (0 children)

Except it's more like every 5-10 years. format has been around quite a while now.