Why does this need to be a language feature. This could just be a separate library, we could use brackets instead of a letter before a string. I fear, Python is going down the path of C++
It being a language feature gives you controlled access to the lexical scope, such that the template string can refer to variables by name rather than having to pass each value as a parameter. Doing it via parameters is repetitive and/or error-prone.
Will this allow neat SQL syntax like the following?
city = 'London'
min_age = 21
# Find all users in London who are 21 or older:
users = db.get(t'
SELECT * FROM users
WHERE city={city} AND age>{min_age}
')
If the db.get() function accepts a template, it should, right?
This would be the nicest way to use SQL I have seen yet.
Thanks, I hate it. While it's nice syntactic sugar, the difference between an SQL injection vulnerability and a properly parametrized query is now a single letter that's easily missed
The t-string produces a Template object without a __str__() method. You can’t mistakenly use an f-string in its place. Either the code expects a string, in which case passing it a Template would blow it up, or the code expects a Template, in which case passing it a string would blow it up.
I guess that is a misunderstanding on your side, about how templates work. Less hate and more love might help to avoid this type of hotheaded misconception ;-)
Why do you think changing a letter would cause a vulnerability? Which letter do you mean?
Not sure about introducing yet another string prefix. Between f-strings, raw strings, and i18n stuff, it’s already getting crowded. Curious how readable this will be in large codebases.
How would this be different from a function sql() that operates on one of these new t-strings?
The syntactic sugar of changing it from sql(t"...") doesn't seem particularly valuable. The novel thing about t-strings is that they change the parsing at compile-time.
Additionally, it will probably be confusing that it is called a t-string but it is actually a constructor for a Template object and not string at all. I would rather see a new special term `template` than this.
It’s injection safe and compostable, and the resulting object retains the original values you interpolate in. This makes it useful for building SQL queries with prepared arguments for example.
It’s on a meta level: instead of formatting the string, it returns an object that contains both the format string and its argument. Library author can then implement whatever format function they want, for example one that escapes the interpolated strings.
Sure, this avoids issues with SQL injections. However, I have a hard time imagining any developer who would both make such fundamental errors with f-strings currently and also switching to this option when it ships.
Seems like a self selection which renders this meaningless, to some extent :/
> However, I have a hard time imagining any developer who would both make such fundamental errors with f-strings currently and also switching to this option when it ships.
t-strings are a different type (both static and dynamic), f-strings are not. So t-strings can be mandated at the API level, forcing the developer into "proper" usage.
That is, you need third-party tools to differentiate between
some_call("safe literal string")
and
some_call(f"unsafe dynamically created string")
That is not the case when it comes to t-strings, `some_call` can typecheck internally that it got a t-string, and reject regular strings entirely.
Although some space probably needs to be made for composing t-strings together in case of e.g. runtime variation in items or their count. Facetting for instance. I don't know if that's a native affordance of t-strings.
sqlalchemy doesn’t really accepts strings - if you do, you need to pass them into a “conn.execute(text(…))”, so end users should not face a breaking change.
I enjoy f-strings, I guess some people need these.
And I love Python but, having been through 2->3 ( occasionally still going through it! ) whenever I see a new language feature my first thought is "Thank goodness it doesn't break everything that went before it".
Yeah but it's been 17 years, maybe it's time to put the PTSD behind us. We're almost at a point where the current generation of programmers wasn't even programming when that happened.
> We're almost at a point where the current generation of programmers wasn't even programming when that happened
I've been programming with Python since 2006, I think most of the systems were based on 2.4 at the time. I've been one of those who switched to Python 3 somewhat late, waiting for some major libraries to ship python 3 packages - celery and Twisted were one of the biggest holdouts - so I remember that the first project where all my dependencies were ready for python 3 was around 2015.
This is to say: even seasoned developers who were conservative around the migration have spent more time working with Python 3 than Python 2. There simply is no reason anymore to be talking about python 2.
Python2 code didn't disappear when Python3 came out. At my work we're _still_ occasionally having to help people migrate code that was written for python2
If this is just for sql queries ... it'd be overkill especially where you need to compare the usual PREPARE statements with the hassle of keeping everyone on 3.14 and above.
Why does this need to be a language feature. This could just be a separate library, we could use brackets instead of a letter before a string. I fear, Python is going down the path of C++
It being a language feature gives you controlled access to the lexical scope, such that the template string can refer to variables by name rather than having to pass each value as a parameter. Doing it via parameters is repetitive and/or error-prone.
Will this allow neat SQL syntax like the following?
If the db.get() function accepts a template, it should, right?This would be the nicest way to use SQL I have seen yet.
The SQLite extension for Tcl offers something similar:
https://sqlite.org/tclsqlite.html#the_eval_methodThanks, I hate it. While it's nice syntactic sugar, the difference between an SQL injection vulnerability and a properly parametrized query is now a single letter that's easily missed
The t-string produces a Template object without a __str__() method. You can’t mistakenly use an f-string in its place. Either the code expects a string, in which case passing it a Template would blow it up, or the code expects a Template, in which case passing it a string would blow it up.
Type checkers to the rescue ahaha I think db.get could also raise if the type does not match?
I guess that is a misunderstanding on your side, about how templates work. Less hate and more love might help to avoid this type of hotheaded misconception ;-)
Why do you think changing a letter would cause a vulnerability? Which letter do you mean?
OP is referring to swapping t with f.
That would result in a string passed to get() and raise an error as get() operates on a template, not on a string.
except if get() can also accept a raw string, which is likely
f'' vs t'' probably.
Those are two different types
Wow that's only slightly better than using the lowercase letter L vs the digit 1 or letter O vs zero to convey a significant difference.
Big discussion (414 points, 10 days ago, 324 comments) https://news.ycombinator.com/item?id=43647716
It feels a bit like "cheating" that new x-string features are built-in only. It would be cool to be able to do:
A t-string is a literal for a Template object which is a data hoilder, it doesn't actually do anything, so you would simply call
Use a function?
It’s just syntax, like we used to have that later becameTrue. Then you could use
for each of the given examples and achieve some runtime type safety.Will it be a performance boost if Django's template engine started using t-strings internally?
Maybe this could be useful to libraries like psycopg3 to use something more simple/natural instead of this:
https://www.psycopg.org/psycopg3/docs/api/sql.html
(while I also agree it gets crowded with yet another string prefix)
That's the exact use case. Basically these are syntactic sugar for a very similar function signature.
Looks useful for embedding interpreters
Not sure about introducing yet another string prefix. Between f-strings, raw strings, and i18n stuff, it’s already getting crowded. Curious how readable this will be in large codebases.
I'm of the opposite opinion. Let's set the prefixes free!
This was considered and rejected: https://peps.python.org/pep-0750/#arbitrary-string-literal-p...
How would this be different from a function sql() that operates on one of these new t-strings?
The syntactic sugar of changing it from sql(t"...") doesn't seem particularly valuable. The novel thing about t-strings is that they change the parsing at compile-time.
> The syntactic sugar of changing it from sql(t"...") doesn't seem particularly valuable.
It's valuable because:
- IDEs could then syntax-highlight SQL inside of SQL strings and HTML inside of HTML strings
- You can't accidentally pass an HTML string to your SQL library
It wouldn't be different, but it would be more convenient because we no longer have to count the number of %s, you'd put the variable inline.
That's... already the case of t-strings?
Yes, that's my point. The GP was already talking about a t-string.
dmurray was comparing a hypothetical sql"..." with sql(t"..."). There are no %s either way.
This is how JavaScript does it with tagged template literals.
Your sql there would just be a function that receives the array of strings/values and returns whatever.
"Yet another" is not my main worry
The concept of prefixes itself feels a little deviant from readable code that is close to human language -- which is the spirit of Python
Additionally, it will probably be confusing that it is called a t-string but it is actually a constructor for a Template object and not string at all. I would rather see a new special term `template` than this.
The single letter f or t does make it unnatural to read, but if it were sql"..." or html"...", I think that would help with that.
Are there string prefixes for i18n stuff?
They're probably talking about the convention of using _ as an alias for `translate`
Nice, so it's a kind of "limited DSL" inside python that's easy to extend
what's the tldr difference between this and .format ?
It’s injection safe and compostable, and the resulting object retains the original values you interpolate in. This makes it useful for building SQL queries with prepared arguments for example.
[flagged]
It’s on a meta level: instead of formatting the string, it returns an object that contains both the format string and its argument. Library author can then implement whatever format function they want, for example one that escapes the interpolated strings.
It’s custom .format implementation. (You access the placeholder and value and produce the string)
Sure, this avoids issues with SQL injections. However, I have a hard time imagining any developer who would both make such fundamental errors with f-strings currently and also switching to this option when it ships.
Seems like a self selection which renders this meaningless, to some extent :/
> However, I have a hard time imagining any developer who would both make such fundamental errors with f-strings currently and also switching to this option when it ships.
t-strings are a different type (both static and dynamic), f-strings are not. So t-strings can be mandated at the API level, forcing the developer into "proper" usage.
That is, you need third-party tools to differentiate between
and That is not the case when it comes to t-strings, `some_call` can typecheck internally that it got a t-string, and reject regular strings entirely.Although some space probably needs to be made for composing t-strings together in case of e.g. runtime variation in items or their count. Facetting for instance. I don't know if that's a native affordance of t-strings.
But that would require any SQL library you're currently using to make the breaking change of no longer allowing strings.
sqlalchemy doesn’t really accepts strings - if you do, you need to pass them into a “conn.execute(text(…))”, so end users should not face a breaking change.
I enjoy f-strings, I guess some people need these.
And I love Python but, having been through 2->3 ( occasionally still going through it! ) whenever I see a new language feature my first thought is "Thank goodness it doesn't break everything that went before it".
Yeah but it's been 17 years, maybe it's time to put the PTSD behind us. We're almost at a point where the current generation of programmers wasn't even programming when that happened.
> We're almost at a point where the current generation of programmers wasn't even programming when that happened
I've been programming with Python since 2006, I think most of the systems were based on 2.4 at the time. I've been one of those who switched to Python 3 somewhat late, waiting for some major libraries to ship python 3 packages - celery and Twisted were one of the biggest holdouts - so I remember that the first project where all my dependencies were ready for python 3 was around 2015.
This is to say: even seasoned developers who were conservative around the migration have spent more time working with Python 3 than Python 2. There simply is no reason anymore to be talking about python 2.
Python2 code didn't disappear when Python3 came out. At my work we're _still_ occasionally having to help people migrate code that was written for python2
If this is just for sql queries ... it'd be overkill especially where you need to compare the usual PREPARE statements with the hassle of keeping everyone on 3.14 and above.
Could also be used to prevent html injection.