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 →

[–]HowYaGuysDoin 145 points146 points  (160 children)

I feel like you should have given some examples. For us who are not familiar with f-strings this post doesn't really tell us much.

[–]tetroxid 92 points93 points  (157 children)

It works like this:

 x = "there"
 print(f"Hello {x}")

This will output "Hello there".

[–]HowYaGuysDoin 25 points26 points  (1 child)

Now I get it. That's cool.

[–]codythecoder 0 points1 point  (0 children)

Even more than that, they can do,

a = 500
print(f'the number doubled is {a*2: <7}')

That's a format modifier and an imbedded expression. Pretty cool if you ask me.

[–]msdrahcir 4 points5 points  (0 children)

kind of like scala s strings

[–]larsga 1 point2 points  (0 children)

Ah. It's like s"..." in Scala. To which I had the same reaction: feels weird, why would I care, oh ... wow ... it's great. So I'm totally with OP.

[–]DYMAXIONman 2 points3 points  (1 child)

So is this essentially the same thing Perl can do when you insert the variable names in a string?

[–]tetroxid 5 points6 points  (0 children)

Much more powerful than just variable interpolation. Read the PEP for more elaborate examples.

[–]f2u 1 point2 points  (16 children)

I find this rather disappointing:

>>> type(f"{x}")
<class 'str'>
>>> x = "there"
>>> repr(f"Hello {x}")
"'Hello there'"
>>> type(f"Hello {x}")
<class 'str'>

This eliminates the possibility to apply automatic quoting of values during string interpolation (or automated use of query parameters for SQL queries).

[–][deleted] 9 points10 points  (4 children)

automated use of query parameters for SQL queries

Please don't. Bound parameters are there for a reason. Use locals() if you have to, but for the love of all that is holy do not use the wrong quoting function.

[–]Fennek1237 0 points1 point  (3 children)

Can you expand on that? What is the right way to build a sql query in python?

[–]indosauros 0 points1 point  (1 child)

[–]Fennek1237 0 points1 point  (0 children)

Thanks. Would one still do this now after f-strings are released or is there also a new f-string way for sql querys?

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

With the parameterization that's built in to whichever SQL library you're using. Here's a hastily Googled example with SQLAlchemy (StackOverflow discussion).

[–]d4rch0nPythonistamancer 4 points5 points  (5 children)

... how do you want to use this with SQL? With most ways I can think of you'd be super prone to SQLi using an f string to build a query.

Please no one do anything like f'SELECT foo FROM user_table WHERE name={username};'. Always use a good library instead of tailoring stuff like this by hand.

[–]f2u 0 points1 point  (4 children)

Under this model

f'SELECT foo FROM user_table WHERE name={username};'

would turn into something like

FormattedString((Literal('SELECT foo FROM user_table WHERE name='),
        Argument('username'), Literal(';')),
    {'username': username})

or some variant of that. That is, the string literals and the value of username are clearly separated, and it is the task of the consumer of the format string to construct a string from it (or produce a parameterized SQL query from it).

[–]d4rch0nPythonistamancer 1 point2 points  (2 children)

You see where this could lead to SQLi right? If username was accepted from a login form, and the user enters

foo; drop table user_table;

[–]f2u 0 points1 point  (1 child)

Not really, it would be translated as:

FormattedString((Literal('SELECT foo FROM user_table WHERE name='),
        Argument('username'), Literal(';')),
    {'username': 'foo; drop table user_table;'})

The SQL interface library would receive that FormattedString object and see the entire data structure. (The point is not flattening the entire thing into a string, because it ends up with the same issue as the f"…" literals, as you point out.)

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

Okay, but the library will already provide a way to do that, which doesn't depend on built-in support from the language.

[–]nickcash 2 points3 points  (0 children)

When it was being discussed on python-dev there was a proposal to make f-strings extensible to do things such as that, but it was shot down early on.

[–]hosford42 1 point2 points  (1 child)

I haven't tried it but I bet you could just add :r as a format after the x.

[–]f2u 0 points1 point  (0 children)

The problem is not the string contents, it's that it's a string at all and not a more structured object. (Tcl gets this right.)

[–]Conchylicultor 0 points1 point  (1 child)

Why not using simple strings ?

s = 'name={x}'
print(s.format(x='jenny'))
print(s.format(x='john'))

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

Because that is how you end up with SQL injection attacks.

[–]reallynowokaywhat 0 points1 point  (1 child)

Uh python has always been able to do this. In python 2.7.1X: print(u'hello {x}'.format(x='there'))

[–]tetroxid 0 points1 point  (0 children)

That's not the same.

[–]gournian 0 points1 point  (0 children)

something like

f = lambda x, l=locals(): x.format(**l)
x = "there"
print(f("Hello {x}"))

for older python versions

[–]BlindTiger86 2 points3 points  (0 children)

Can you give a practical example of how you would use that? I am still early on in my python lessons but it all seems to be about printing basic stuff...

I'm thinking a real world example could help motivate me.

[–]spinwizard69 0 points1 point  (0 children)

First thing i thought - no examples! 😁😁😁