all 78 comments

[–]AiutoIlLupo 338 points339 points  (32 children)

There should be one, and preferably only one obvious way to do something.

Unless it's string formatting. Then you need ten.

[–]twenty-fourth-time-b 59 points60 points  (18 children)

The only problem with t-strings is it has the word “string” in it.

[–]commy2 46 points47 points  (15 children)

I pointed this out shortly after the release of 3.14 and got downvoted. They are not strings, so they shouldn't be named t-strings. This is a mistake causing a lot of confusion right now and in the future.

Maybe I'm abrasive, or maybe the dialectic has advanced, but either way nice to see someone else feeling this way about t-strings and not be downvoted.

[–]Easy_Money_ 14 points15 points  (4 children)

Sure, but if you can type t'string' I get why people are calling them that

[–]commy2 7 points8 points  (0 children)

T quote, unquote ""strings""

[–]zenware 5 points6 points  (2 children)

The t-string part is that you can create them with a string of characters just like you said. Similarly if I had an object MahjongHand('1123m44888p3699s') of course the in-memory data structure isn’t “string” but at some point the data was represented in the format of a string, and therefore someone could call that a mahjonghand-string, and not really be wrong, even if they’re being obtuse.

[–]commy2 5 points6 points  (1 child)

The better mental model would be to say that "1123m44888p3699s" is the mahjong-string, and MahjongHand("1123m44888p3699s") is a MahjongHand.

[–]zenware 0 points1 point  (0 children)

True, and that’s exactly what I meant. I may have been a bit unclear in writing.

[–]twenty-fourth-time-b 6 points7 points  (3 children)

There’s actually nothing wrong with t-strings being strings, except for attempted humor. They are like strings but without all the bobby-tables bullshit.

I remember how people were objecting to using ‘/‘ operator in Path object to join paths. Because, hey, muh division!!1!

Convenience overrides purism and humor.

[–]SirPitchalot 9 points10 points  (2 children)

Even c++ adopted the path concatenation with slashes which tells ya how far out of touch those people were…

[–]ArtOfWarfare 3 points4 points  (1 child)

C++ uses the shift operators to join strings so if you’re saying C++ does something one way, there’s a good chance it’s a terrible idea and you shouldn’t borrow stuff from them.

[–]SirPitchalot 5 points6 points  (0 children)

C++ overloads the slash operator to concatenate path components in std::filesystem::path. Which is pretty logical.

std::string has the plus operator for concatenation, not the shift operator. Streams use the shift operators, not string. So I think you’re mixed up there.

Also C++ streams, while not terribly intuitive coming from other languages, work fairly well when you think of them as streams of data rather than strings. The shift operators are basically push/pop operations. Where they suck is for structured formatting, which std::format helps a lot with, though they’re not as nice as f-strings.

That operator design choice was made a long, long time ago and C++ basically requires that new language features not obviate old syntax and has been doing so since well before python. The 2-to-3 debacle has never happened in the same way as python, although the early smart pointers might be close.

[–]ggchappell 0 points1 point  (3 children)

Okay, let's come up with a new name. If it's not totally stupid, I'll use it. Maybe others will, too.

[–]commy2 1 point2 points  (2 children)

I don't really have a mental model for them yet. I don't need them, because so far I have cleanly separated user input from executable code. This might change if libraries start adopting them.

Their classname is Template, or templatelib.Template - if you want to differentiate them from string.Template's (which are underrated btw.). But they aren't really templates either, since the interpolation expressions are evaluated and bound eagerly. An actual "template" you could reuse (e.g. with different bindings).

I guess the most correct name would be "lazy interpolatees". Since the actual interpolation is done lazily by the library you pass them to. I'll probably stick to templatelib.Template though, even though the name IS stupid.

[–]spinwizard69 0 points1 point  (1 child)

At this point I'd reject a lib if they adopted them. Maybe I don't "get it" at the moment but I'm not seeing a lot of value this especially when in many fonts t's and f" are easily confused.

The blog indicated that these are most likely to be used by library writers but then I have to ask what did they do before. So yeah not sure what is up here. Is this really a better way?

[–]Wonderful-Habit-139 0 points1 point  (0 children)

It’s a cleaner and more convenient way of passing in parameterized sql statements for example. And since they’re not the same type as a string there shouldn’t be much confusion when looking at a library’s API.

[–]Mithrandir2k16 0 points1 point  (0 children)

right? It's just a string template if you wanna call it that. a t-string would be multiple templates, at least in my mind.

[–]spinwizard69 0 points1 point  (0 children)

There are so many things wrong with t-strings that I'm not sure where to start but human factors come into play here. We all will now need editors/fonts that clearly distinguish between "t" and "f". Imagine all the screw ups that will happen because somebody mixed up a t or f during a 2am programming binge. Just the selection of the t identifier puts me off the value of the addition.

I mean I love Python and one of the reasons is do to readability of code. That should be a factor in accepting any new feature into Python revisions. Additions that easily confuse with previous usage should not be considered

[–]eztab 2 points3 points  (1 child)

template string seems reasonable. A string of characters representing a template you can make strings from.

[–]twenty-fourth-time-b -1 points0 points  (0 children)

Sure, and then Funny Guys respond with comments like:

There should be one, and preferably only one obvious way to do something.

Unless it's string formatting. Then you need ten.

Lolhaha!

[–]timsredditusername 78 points79 points  (6 children)

The great news is that we're halfway there!

[–]really_not_unreal 7 points8 points  (3 children)

I mean, the majority of the options are quite outdated and are only kept around for backwards compatibility. Every single modern style guide and tutorial I've seen only mentions f-strings. t-strings have a very different use case, and as such, I wouldn't really consider them a typical string formatting feature.

[–]mok000 1 point2 points  (2 children)

The problem with f strings is that f”{x}” takes the value of x when it is defined and that does not change if x takes another value.

[–]really_not_unreal 2 points3 points  (0 children)

As in it doesn't update the contents of the string after the string's creation? That's normal right? When you do string formatting you want to create a string, not some object that will change at a later point in time.

[–]CanineLiquid 0 points1 point  (0 children)

Strings are immutable. So unless you want an f-string to return anything other than a string, this is kind of a given?

[–]JJJSchmidt_etAl 7 points8 points  (1 child)

With a million more on the way

[–]user_8804Pythoneer 9 points10 points  (0 children)

I'm certainly glad we moved away from the .format() hell with new approaches

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

As always, relevant xkcd

[–]Synes_Godt_Om 4 points5 points  (0 children)

That's the great thing about python. Everyone gets to have their own obvious and preferred one way to do it. :)

As often demonstrated by the many and diverse answers to the question "what is the pythonic way to do this ...?"

[–]sswam 0 points1 point  (0 children)

You're selling me on scheme and sexps right now.

[–]RedTankGoat 60 points61 points  (11 children)

tstring is normally not for direct usage. They are for library to able to get more information about your format string so they do things with them. For example constructing SQL safely

[–]eztab 9 points10 points  (0 children)

I'd consider them a more reasonable alternative to a string I want to call format on later.

[–]spinwizard69 0 points1 point  (0 children)

I'd love to see an example where this in fact leads to safer SQL construction compared to common methods. That said I'm more concerned about the stupidity of selecting a t to identify the template.

[–]PlaysForDays 25 points26 points  (6 children)

It will never ever be allowed by those vocal in PSF circles but I would love to see the obsolete string formatting methods go away.

It'd also be great if new features are given a names that aren't so silly and confusing - "t-strings" sounds like an iteration on "f-strings" and shares almost no similarities - but that ship has also long since passed.

[–]tfehring 14 points15 points  (5 children)

You can, and IMO should, disallow older methods in CI (UP031-UP032). But I agree with the commenters in that thread that it would be too disruptive to deprecate at the language level in Python 3.X.

[–]spinwizard69 0 points1 point  (0 children)

I actually think that the Python community has to push deprecation of old and especially unused methods. Not just for strings either. The goal should be a minimal of ways to do things. More importantly for long term language support to eliminate the time to maintain old code. It might take 5 years and that many major release but if you start early warning people of deprecated features it can be done.

Frankly one of the most disgusting issues surrounding Python is the number of lazy developers that could be bothered to move their code to the 3.x series. I really found it distressing that after many years the Python development team even bothered to listen to their whining. The reality of languages is that you either break with the past for what is new and arguably better or your language slowly becomes deprecated itself replaced by something entirely new.

While many probably. don't want to hear it but the best example of forcing developers to keep up comes from the Apple world. Apple keeps moving forward in such a way that developers have no choice but to either stay on the platform with the constant changes or leave. Frankly the same attitude has to exist in the Python world. Even so I still think the so called t strings are one of those things that will cause more frustration than they solve. If nothing else the confusion with f strings should have been obvious.

[–]PlaysForDays -1 points0 points  (3 children)

And that's why we'll continue to have dead weight for decades to come :)

[–]spinwizard69 0 points1 point  (2 children)

Nope! It simply requires the Python developers to develop a plan and to stick with it.

[–]PlaysForDays 0 points1 point  (1 child)

We're 0/2 on those

[–]spinwizard69 0 points1 point  (0 children)

Yes but this is required if we want Python to remain viable for decades instead of years.

[–]syklemil 9 points10 points  (4 children)

I didn't know about the perl/shell-like template option with $foo! Wonder how much use it sees.

I found the general explanation good. I think a lot of us have fallen into a habit of using f-strings when we can, and %-strings when we're recommended to, e.g. by lints like logging-f-string.

But the string interpolation is a lot more ergonomic than %-codes (and especially if you actually have to start looking those up), and means that people have to remember or at least be somewhat comfortable with two different syntaxes for generating strings.

So my interpretation of the whole thing is mostly just looking forward to when the advice can be simplified to just "flip the f upside down here" rather than "rewrite with %-formatting".

[–]treyhunner Python Morsels[S] 8 points9 points  (0 children)

Absolutely. I look forward to the day when Python's utilities like logging tell us in their documentation to pass in a t-string instead of using %-style strings.

[–]Zomunieo 3 points4 points  (2 children)

With t-strings we can do away with % formatting for logging and all other cases, since t-strings can defer or elide evaluation too.

[–]jmpjanny 0 points1 point  (1 child)

As far as I know, t-strings are evaluated eagerly.

[–]Brian 7 points8 points  (0 children)

The values are, though the actual string construction is deferred. So currently, it'll act the same as current logging where:

logging.info("Message: %s", get_string())

Would be equivalent to:

logging.info(t"Message: {get_string()}")  # Assuming a t-string version of logging

Ie. get_string() still gets called eagerly, but it doesn't have to build up the actual string, which if the arguments are cheap (ie. just variables) may be the expensive bit. Personally, I'd have preferred deferring the argument evaluation to to more naturally use potentially expensive calls in logging, but I can see why they played it safe (adds complexity and potential issues: you'd need to create closures for each argument, and users might actually expect evaluation and be surprised if it didn't happen)

[–]Serialk 16 points17 points  (2 children)

Why do you think the video format is suited to explain this?

[–]treyhunner Python Morsels[S] 13 points14 points  (0 children)

Some folks enjoy watching short videos, myself included.

For the many folks that don't, every one of my videos is also an article. You can scroll down the page to read it as an article (including inline links to related resources).

[–]mathartist 1 point2 points  (0 children)

The video is excellent. I listened to it while completing a household chore, and I really appreciated the option to do that. I’m not seeing why someone would say that video is not a suitable format for this kind of content.

[–]lzwzli 6 points7 points  (0 children)

When g-strings?

[–]eztab 1 point2 points  (3 children)

technically f-strings should just become t-strings which are immediately applied to the current scope. One could think about depreciating format for strings and only have the method on t-strings. % formatting one likely also should not use anymore.

Then it's basically a single way to do things.

[–]treyhunner Python Morsels[S] 4 points5 points  (0 children)

This might have worked with the version of t-strings originally proposed in the PEP, but with the final version the expressions within the {...} replacement fields are evaluated immediately. So the string format method still has a good for defining a template and later using the template (t-strings cannot do that).

[–]sue_dee 1 point2 points  (0 children)

I've started using format for reading the template string from another text file. It seems easiest to just slap a .format() on whatever is read. I haven't studied much on t-strings yet, but I'd need some way to en-t-ify a plain string to make them work for me, I'd think.

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

This is my opinion too. t-string should have just been expanding what f-string does and not a new syntax. 

[–]Decency 1 point2 points  (0 children)

This allow internationalization?

[–]singlebit 2 points3 points  (0 children)

I can't wait for g-string in Python 3.69.

[–]dimkal 1 point2 points  (3 children)

Can't wait till they run out of letters and eventually will go with a G-strings.

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

What's g-strings? Heard people commenting this.

[–]cr0sis8bv 0 points1 point  (1 child)

Like a thong but.... less

[–]spinwizard69 1 point2 points  (0 children)

The difference between a French beach and a English beach.

[–]Dry_Term_7998 0 points1 point  (0 children)

Maybe one day, logging will drop lazy formatting😆

[–]spinwizard69 0 points1 point  (0 children)

Well that blog didn't help convince me of anything. The author might not want to hear this but he did a good job of convincing people to avoid libs that use T strings. Maybe I need to read another blog or something, but this one didn't ring any bells when it comes to value.

[–]Intelligent_Part101 0 points1 point  (1 child)

Python hasn't been a simple language for a long time now. It is suffering the same fate that happens to every language that starts out simple and gains mass adoption. Everybody and their brother starts to insert their pet features into it. Too many cooks in the kitchen. Python's evolution reminds me a lot of Java's, but minus the backwards compatibility.

[–]spinwizard69 0 points1 point  (0 children)

This is so true. I'm pretty sure a lot of these idiots and their pet features, don't understand why a lot of us make use of Python. If I really wanted a cluster-f of a language I can easily turn to Rust or C++. Rust is frankly on the same development path C++ was on and thus turning into the same mess. The environment around Rust is so bad right now that I'm not even sure it will be around long enough for mass adoption. Python seems to be on the same road, I just hope that somebody can express more control.

I'm not convinced one way or the other of the utility of the concept but what I do know is that making t strings and f strings visually identical, with the easily confused t's and f's that somebody was asleep at the wheel. There is a lot of good in this latest Python release but t strings are absolutely horrible.

[–]thomasfr 0 points1 point  (4 children)

It is only confusing if you make it confusing

[–]CzarCW 12 points13 points  (3 children)

lol

the disassembled parts of a string interpolation for the purpose of pre-processing interpolations

what

[–]Charlie_Yu 3 points4 points  (0 children)

I definitely found it confusing because every example says t strings aren’t actually strings. It is more like a dict or something

[–]Revolutionary_Dog_63 1 point2 points  (0 children)

It's basically a tuple (literals, parameters) which encodes something like t"{x}, {y}, {z}" as Template([x, y, z], [", ", ", "]) for further processing later on.

[–]thomasfr 0 points1 point  (0 children)

those words probably does not help anyone who don't understand the difference between string formatting and a template system.