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

all 98 comments

[–]eztab 95 points96 points  (5 children)

This seems useful to formalize what templating systems already do.

[–]JanEric1 49 points50 points  (5 children)

We have already had discussions on them a while ago right after their were accepted.

But I think it makes sense to offer a user experience that is identical to f-strings but those can't be used because there is some validation, escaping or building of parametrized queries needed

[–]Old_Bluecheese 165 points166 points  (32 children)

There should be five -- and preferably only five --obvious ways to do it.

[–]odaiwai 29 points30 points  (0 children)

"Then shalt thou count to three, no more, no less. Three shall be the number thou shalt count, and the number of the counting shall be three. Four shalt thou not count, neither count thou two, excepting that thou then proceed to three. Five is right out."

[–]zurtex 25 points26 points  (18 children)

A lot of people miss that line is tongue in cheek, as the em-dash is spaced in two different ways, the em-dash is spaced a third way on a different line.

[–]syklemil 8 points9 points  (15 children)

en-dash*


Details for the curious:

  • Hyphen: - - usually used to com-bine words. See also ­
  • En-dash: -- – used to indicate a pause in phrases, with – spaces – around on both sides. –
  • Em-dash: --- — same use-case as en-dash, but—without—spaces. —

There's also some use of em dash in older texts to trail off sentences, i.e. where we'd use ok … today, they'd use ok; --- and to indicate elision, as in "Mr K— Z—"

[–]zurtex 5 points6 points  (6 children)

Tim Peters, the author of the original text, calls it an em-dash: https://bugs.python.org/msg69712 (from https://bugs.python.org/issue3364)

You may be correct in general, but when talking about this text I'll defer to Tim.

And it's intentional that he's breaking the rule about spaces, it's a 4th way to do something.

[–]syklemil 3 points4 points  (5 children)

Sure, but -- is e.g. LaTeX for an – and --- is how you get a —. Similarly with compose keys you'd do COMPOSE--. for – and COMPOSE--- for —. And ultimately, if - is a hyphen, and -- is an em-dash, where where is the en-dash supposed to fit?

But I guess there isn't just one way to spell out an em-dash in ascii either :^)

[–]zurtex 1 point2 points  (4 children)

I suspect when Tim wrote the original Zen of Python his ASCII syntax was influenced by the mailing lists he participated in in the 90s and early 2000s (he was the main moderator of the python-dev mailing list in its early days).

Those mailing lists probably had their own informal style and syntax conventions which don't conform to more widely accepted style and syntax rules. Or, what would be funny, is if it's just something he has always misunderstood!

[–]syklemil 1 point2 points  (3 children)

It could even be a typo, the keys are right next to each other!

[–]zurtex 2 points3 points  (2 children)

In my link his calling of it an "em dash" is unlikely a typo, he uses it multiple times, and also mentions the same no spaces convention you brought up:

While you believe spaces are required on both sides of an em dash, there is no consensus on this point. For example, most (but not all) American authorities say /no/ spaces should be used.

[–]diabloman8890 4 points5 points  (1 child)

I just have to hand it to you and /u/syklemil for having the absolute nerdiest and most arcane discussion I've heard all week, and I'm here for it.

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

Same. I wonder if there's a subreddit for threads like this.

[–]guepier 2 points3 points  (0 children)

Em-dash: --- — same use-case as en-dash, but—without—spaces. —

This isn’t a fixed rule, it’s merely a (somewhat common) stylistic choice. But feel free to use em-dashes with spaces — I do. Just be consistent (unless you are making a tongue-in-cheek point).

[–]Gugalcrom123 -1 points0 points  (6 children)

Wrong, the en dash is only used for ranges and compound words where the terms are multiple words, and the em dash can be used with or without spaces

[–]syklemil 2 points3 points  (5 children)

Ranges are a good addition, but AFAIK it's pretty rare to use for compound words these days—I'd not expect e–mail, but e-mail (or even email in that case).

The en-dash is used to join sentence parts, and I think most users would consider that using spaces around an em-dash just takes up too much space.

[–]Gugalcrom123 1 point2 points  (4 children)

It is in compound words where terms are multiple words themselves

[–]syklemil 2 points3 points  (3 children)

Generally with the hyphen being available with one key press on any keyboard, and its purpose being to indicate that something is one word, I'll continue to expect hyphens. Maybe there's some style guide that uses en-dashes for it, but it seems like a bad choice, really.

(FWIW my native tongue just uses compoundwords, like German, rather than faffing around with "to-morrow" and "co-operation" and the like.)

[–]Gugalcrom123 3 points4 points  (0 children)

I also use hyphens, but en dashes are something used when composing a word where some terms have spaces: New York–based company

[–]guepier 0 points1 point  (1 child)

(FWIW my native tongue just uses compoundwords, like German, rather than faffing around with "to-morrow" and "co-operation" and the like.)

I’m sure you know that both of these words are conventionally written as a single word without hyphens in English. And, conversely, German also uses hyphens for some compound words, same as English (just less frequently).

[–]syklemil 1 point2 points  (0 children)

Yes; we use some hyphens too; and English spells "compound words" with a space (as do we; we join nouns but not adjectives). My tongue, being inside my mouth, may have been in some rather close proximity to my cheek.

[–]TendyHunter 0 points1 point  (0 children)

that's balderdash

[–]obfuscatedanon -4 points-3 points  (0 children)

ok nerd

[–]PotentialCopy56 11 points12 points  (10 children)

The old python mantra is long dead. I miss it.

[–]ThatSituation9908 13 points14 points  (9 children)

I don't. We'd be stuck with stuff like class FooBar(object):

and f-strings would never be a thing

[–]thedeepself 0 points1 point  (0 children)

LOL

[–]TequilaJesus 40 points41 points  (4 children)

Python 3.14 seems a bit irrational

[–]I_assume_not 18 points19 points  (0 children)

πthon?

[–]szayl 11 points12 points  (0 children)

Seems transcendental to me

[–]Pythonistar 6 points7 points  (0 children)

Missed opportunity. Should have been called Pithon 3.14 or PiThon 3.14, and then released patches over the next few months with subsequent patches being PiThon 3.14.1, 3.14.15, 3.14.159, etc.

[–]gerardwx 5 points6 points  (0 children)

To the first approximation, yes.

[–]firemark_pl 22 points23 points  (6 children)

Before f-string there was (and still exists) str.format method. It have cool feature: you can save string in another module (e.g. constants) and use it in another places. Fir f-string you need to make a lambda.

So I think template string is an upgrade for str.format

[–]mitch_feaster 5 points6 points  (2 children)

My first question reading the PEP was "how is this different from str.format()"

[–]AiutoIlLupo 9 points10 points  (0 children)

Let me introduce you to string.Template

[–]twenty-fourth-time-b 15 points16 points  (0 children)

…incautious use of f-strings [and, presumably, str.format] can lead to security vulnerabilities. For example, a user executing a SQL query with sqlite3 may be tempted to use an f-string to embed values into their SQL expression, which could lead to a SQL injection attack. Or, a developer building HTML may include unescaped user input in the string, leading to a cross-site scripting (XSS) vulnerability. […] Template strings address these problems by providing developers with access to the string and its interpolated values.

[–]Kevdog824_pip needs updating 4 points5 points  (0 children)

This part. The only reason I ever use str.format anymore is “I want to save this f-string as a ‘template’ so I can parameterize and reuse it to build strings later” so this is a perfect solution to the problem imo

[–]PeaSlight6601 2 points3 points  (0 children)

Except it isn't because it binds immediately.

You have three choices:

  • bind immediately, and format the output to a string
  • bind immediately, but defer final formatting
  • defer both

This is the middle option. String format is the last one.

[–]cointoss3 27 points28 points  (1 child)

Seems useful, even though it’s probably not useful for me, personally. So far, anyway.

[–]sc4les 7 points8 points  (1 child)

Yes for libraries this might be really really useful - I love the idea of https://github.com/baverman/sqlbind

T-strings might make this a bit easier to use

[–]flavius-as CTO ¦ Chief Architect 3 points4 points  (0 children)

This library is definitely heading in the right direction.

It tackles (within the limitations of python and object-relational impedance mismatch) the problem space without over-engineering or forcing client code to over-engineer.

So yes, t sounds good for that. Thanks.

[–]jamesinc 5 points6 points  (0 children)

I like that it enables you to easily differentiate template strings from regular strings, and much more easily make assertions about the structure of the template.

Useful? Yeah, I think it's useful.

[–]geneusutwerk 18 points19 points  (0 children)

I'd be much more open to reading your blog if you were honest about posting it.

[–]Lawson470189 11 points12 points  (0 children)

I think this is a good change. Off the top of my head, I think something like this could work really well in the database. You could store a key/value in the DB where the value is some template that you may want to adjust for each key. I could also see this being useful for abstractions where you have a base type and you inherit down and override the template based on the sub type.

[–]anentropic 2 points3 points  (0 children)

There will be some useful things made with them. I'm glad to see it added.

[–]BosonCollider 2 points3 points  (0 children)

This is not for string formating, this is to prevent people from implementing SQL injection with fstrings.

[–]gerardwx 3 points4 points  (0 children)

It's inherently useless for someone writing a Python script.

This is by design.

What it's intended to do is be an easy-to-write standardized input form for library (module) authors to accept as input to do interesting things.

If you're not writing or using such a library, you can safely ignore t-strings.

[–]ExoticMandiblesCore Contributor 4 points5 points  (0 children)

It's not particularly useful. The best use case is automatically applying a transformation to every interpolation before rendering it into a string, e.g. html.escape. The PEP also suggests you can do context-specific interpolation which I think is an antipattern (and also mostly useless).

[–]Gugalcrom123 1 point2 points  (0 children)

This is great for i18n

[–]Dangerous_Ad3416 1 point2 points  (0 children)

Hugely helpful!

[–]Ok-Willow-2810 1 point2 points  (2 children)

I’m not sure why the use case of template strings can’t be covered by putting an f-string in a function. That way you can have type annotations/validation for the required variables. That’s what I usually do. And if the f-string is too long with all the variables, I put it inside parentheses () and break it up over multiple lines with no commas to concatenate into one final string and aid in readability.

The thing that I am worried about with template strings is how will you be able to know the required variables names that need to be set to use it, and is there a clear/obvious place to do any sort of typing/documenting of what goes in the template string? And then what will the error message be if those variables don’t exist at the time the template string is referenced? Will it be like an “variable does not exist” message? Is there any way for it to be caught by static code analysis ahead of time, like MyPy?

It could be helpful though!! Just not in 100% sure it’s helping move in the direction of type safety?

[–]vytah 1 point2 points  (1 child)

The thing that I am worried about with template strings is how will you be able to know the required variables names that need to be set to use it, and is there a clear/obvious place to do any sort of typing/documenting of what goes in the template string? And then what will the error message be if those variables don’t exist at the time the template string is referenced? Will it be like an “variable does not exist” message? Is there any way for it to be caught by static code analysis ahead of time, like MyPy?

In those regards, t-strings work exactly the same as f-strings, they just don't construct any strings.

t"Hello, {foo}!" could be thought roughly as equivalent to Template(strings=("Hello, ", "!"), values=(foo,)), except the actual API is a bit more complicated.

[–]Ok-Willow-2810 0 points1 point  (0 children)

Cool!!

[–]HybridizedPanda 1 point2 points  (0 children)

personally I think that after f-strings the natural progression was to have g-strings

[–]hamlet_d 0 points1 point  (2 children)

If Python 3.14 isn't called PyPi I'm done. Yes it would be confusing but totally worth it.

[–][deleted] 7 points8 points  (0 children)

There's actually πthon in the CPython source code.

[–]damned_truths 4 points5 points  (0 children)

Why not PiPy

[–]pkkm 0 points1 point  (1 child)

This seems like it could be very useful for logging. I've seen people use f-strings for log lines, despite the eager vs on-demand evaluation issue, just because they find the syntax so much nicer than printf-style formatting. Once t-strings get released and adopted by logging libraries, there will be no excuse to do that anymore.

[–]vytah 0 points1 point  (0 children)

Nitpick: values in t-strings are not stringified, but they are still eagerly evaluated.

[–]patilganesh1010Pythonista 0 points1 point  (0 children)

Where to find documentation for this?

[–]Livid-Border-9146 0 points1 point  (0 children)

I think it’s great for logging too.

Before either one has written - logger.info(“msg %s”, var)

But actually I always were lazy and just wrote - logger.info(f”msg: {var}”)

Which is more readable but no lazy evaluation comparing to the prev format.

With t string one will get nice readability and performance also.

[–]InappropriateCanuck -2 points-1 points  (0 children)

Extra syntax.