Changing the delimiter is a vaild idea. As discussed above there’s a slight complication because simple keyword args may conflict with existing usages because any name could be used as argument. Personally, I tend towards that the idea would be reasonable on a green field, but given the given the %-format is already there, it’s too much effort for too little gain. Anyway, this should be discussed separately.
An additional motivation for keeping the %-format string and only changing the way arguments are passed to the .pformat() method instead of the % operator is that the migration path is much simpler compared to changing the formatting notation.
You could basically search replace " % (\w+) → ".pformat(\1). - It’s slightly more complex that that, but I could very well imagine that linters/style checkers like ruff can detect these cases reliably and offer automatic conversion. This is much simpler than converting a %-format string to a {}-format string. This enables users to painlessly migrate away from the %-format operator.
This would also open up an IMHO viable path to depreacate and remove the %-format operator in the long run if desired. I’ve intentionally left this out in the original motivation because the nuances between “makes it easier/viable to consider deprecation of” and “will drive the deprecation of” easily get lost in discussions. And to be clear: I don’t want to go into that deprecation discussion right now, but the existing %-formatted code is a blocker and it’s an added benefit that this proposal here could unblock that discussion.
It’s the only motivation presented in the original post:
In my personal opinion %-formatting is antiquated because it has been supplanted by regular (f-strings and format calls) formatting. As further evidence, many Python linters rightly nudge you to convert %-formatting to regular formatting.
Thanks, good idea. I may do that, or someone else is more than welcome to.
As was pointed out by a couple people, regular formatting supports anonymous fields, so there is no such advantage for %-formatting. Do you have any other reasons why you believe that %-formatting has not been supplanted by regular formatting (f-strings or format calls)?
If we are on the same page that %-formatting has been supplanted for nearly all use cases, then you may want to consider the cost of preserving %-formatting. Namely, the cognitive load. Of course, if you’ve been programming in Python for decades, then the cost to you is small since you’re familiar with %-formatting. But if you started in Python <5 years ago, you may only rarely have come across it. For such new developers (and some of us older ones who don’t like reading manuals), it’s a joy to be able to only consider regular formatting. I think we should work towards such a reality. And that means making an effort to use regular formatting and avoiding %-formatting.
Yes, I understand your point. I think I’m coming at it from the opposite angle. I wish %-formatting were used less. I honestly have trouble keeping track of both regular and %-formatting at the same time. The meta-languages are already hard enough to individually keep in mind.
I would have agreed with you 5 years ago, but now Ruff already does it for you, and AI probably does it too. So, you can already convert to regular formatting fairly painlessly.
And many don’t, disputing the “rightly” in that. Percent formatting isn’t supplanted, it’s supplemented.
You have to have (a) started in Python recently, (b) never come across percent formatting, and importantly (c) never used any other language with printf-style formatting.
Why does Python support regular expressions when it would be easily possible to come up with something more Pythonic? Because regex syntax is consistent across languages. This is a huge feature.
This is only a reality if you create a closed ecosystem where no code is written in any language other than Python. That is highly limiting. If you truly want a world in which people need only learn one formatting minilanguage, it would undoubtedly be printf style, as it has broad support across different languages. Fortunately, we don’t need such a world, as both format string types are useful.
All of which are easily and obviously true for a majority of new python users. This number is easily in the hundreds of thousands, maybe even millions. Don’t forget that python is a popular (the most popular?) introduction language in schools, university, online courses, …
And there is a pretty good chance that a decent percentage of these people never use or learn another language because they focus on e.g. scientific work.
Additionally the other most popular languages many will encounter (JS, VB, spreadsheet formular) don’t support percent formatting at all. Neither does rust.
Percent formatting is antiquated and braces based formatting is the future (as agreed upon by python, JS, rust and many others). I personally don’t know what do based on this fact; I don’t think we can deprecated the operator within the next 10 years, probably not even 20 years.
I’m aware of that, but my point is, we don’t NEED a world with just one formatting minilanguage. There is no reason to deprecate it, and it has not been deprecated.
As someone with less than 2 years in Python, but with ~12 years in other, I must say it doesn’t matter. I’m still going to docs, for anything more complex than %d. Yes, there are printf-likes in other languages, but all of them are different in some way, and I’m not gonna make a bug just cause of bad memory.
The hard part is:
It’s a mod operator. It feels like C++'s left-bitshift (std::cout << ...). Why be intentionally confusing?
99% of time, f-string/format is learned first. The other, only after seeing it or searching for exactly printf-style.
I think the main point here is simply that there are still many thousands (probably millions) of lines of code that use % formatting and the % operator. Breaking that code (even if we provide a replacement way of doing the same thing) is likely to be incredibly disruptive - and worse still, code that still uses % formatting is likely to be older code, possibly in “minimal maintenance” mode. Nobody will be willing to undergo a major refactoring on such code.
Adding new features, like the proposed .pformat method, is a lot easier. But the “people don’t use %-formatting any more” arguments do apply here. The benefits of adding extra features to help people using a formatting method that’s not the first choice for newer code are likely to be very small, so justifying the maintenance cost of adding those features is quite hard.
tl;dr; It’s not likely to go away, but there’s little reason to spend time improving it.
YMMV, but you probably need to get some support from a core dev if you expect any of this to go anywhere. And I think that will be hard.
Add to that that there are more than a few methods to make the operation as a call, if, for example, some refactoring that involves older code mixed with new style needs to pick programatically the string formatter - which is the only use case I can find for a new callable.
(Namely, we have str.__mod__, operator.mod and string.sprintf) .
Going off topic for this thread, but if one wants one extra, “seemingly redundant but acually useful”, str method, I might suggest a callable to check if a string is a valid integer or a valid float - because so far we have 3 calls that check if the string contents are digits, but do nothing else (str.isdigit, str.isdecimal and str.isnumeric)- so, for the trivial case of converting a user input to a number (say, "-23.2"), we still need a try...except ValueError everywhere, or reinvent an ad-hoc validator/parser.
Thanks for the reminder. I’m trying to lay out a differentiated case for the benefits of a .pformat() method. It’s in between “leave the quirky %-operator in place as a first class language feature” and deprecating it.
An annoying aspect with the %-operator is that the docs do not clearly discourage it (I’m not calling for deprecation or breaking existing code). I would like to see a clear statement “do not use the %-formatting operator for new code”. But instead, there’s a dance of words with “new format”/“old format” (link), “quirks”, “may help avoid errors”, “Each of these alternatives provides their own trade-offs and benefits of simplicity, flexibility, and/or extensibility.” (link). I assume this is because one did not dare to steer people completely away from %-placeholders because there are still a few use cases where people prefer %-placeholders (see below). IMHO clearly discouraging the %-operator would be a win for the language. If that can be done without addtions to the language, great. If not, a .pformat() method may be the missing bit to convince everybody that there is no reason to use the %-operator in any new code.
“people don’t use %-formatting any more” is generalizing a bit too much. While it’s not the first choice for the majority of use cases, there are still some cases where people still
prefer %-placeholders for new code, as expressed in this thread and Deprecate str % format operator. It’s a nuissance they then have to use the quirky %-operator.
I may not understand the full maintenance implications for the concrete case, but I would have guessed that the added code is basically the C equivalent of
def pformat(self, *args, **kwargs):
if args and kwargs:
raise TypeError(
"'pformat' does not simultaneously accept positional and keyword arguments"
)
if args:
return self % args
else:
return self % kwargs
so it’s not too much or too complicated. Also, it’s unlikely that this code will need to be modified in the future. I therefore naively assumed the maintenance cost is small.
Rhetorical question - why not fix the quirks, then?
The answer is clearly “because we don’t want to put maintenance effort into %-formatting, as f-strings are the modern approach”. The pformat method also involves putting maintenance effort into %-formatting, so you’ll get the same resistance.
I’ve only been skimming technical details here, but can’t pformat be written as a standalone function, in pure Python? Because if so, getting it added as a recipe in the docs, or publishing it on PyPI (or maybe both) might well be the path of least resistance here. Sure, it might not be as “natural” as a method[1], but it may still be better than a long debate that results in rejection…
Another thing to consider is whether str.pformat could use format like other methods do e.g.:
>>> from decimal import Decimal as D
>>> d = D(11111111111111111111111111111)
>>> d
Decimal('11111111111111111111111111111')
>>> '{:f}'.format(d)
'11111111111111111111111111111'
>>> f'{d:f}'
'11111111111111111111111111111'
>>> '%f' % d
'11111111111111111869590405120.000000'
I’d like to differentiate “we don’t want to put maintenance effort”. It’s a trade of beween how much effort is needed and what the gain is. My argument is that the needed effort is really limited. But the gain is that we can clearly state “do not use %-operator formatting in new code” and users who still want %-placeholders can safely use them.
It sure could be a standalone function, that’s basically the code in %-style formatting method - #30 by timhoffm interpreted as a standalone function. But it would have several draw backs to the point of not being worth it:
IMHO nobody would or should add a dependency just for such a function. Python not javascript
Copying the code from a recipe is cumbersome.
The .pformat() has a strong similarity to the .format() method - positional and named parameters are handled in the same way. Only the placeholder format is different. That’s easy to learn and remember. We’d loose that with a standalone function.
In the end, I suspect nobody would use it and people would stick with the %-operator if they want to use %-placeholders.
Yes, it can, and I suggested this exact solution early on:
It fixes the problems, at a whopping cost of two lines of code. I like percent formatting, I don’t like the quirks of the modulo operator, and this one function solves that for all three types (str, bytes, bytearray) polymorphically.
This thread has gone round and round in circles, but perhaps at this point, the right question to ask is: Which core dev would sponsor this proposal? And if the answer is “nobody”, then the sprintf function can go into the toolboxes of those who want it, and everyone else can happily carry on using whichever formatting minilanguage they like, since both are very much still supported.
The fact that %-formatting is restricted to a few types and is not extensible make it a dead end. I don’t think it’s worth inventing ways to make it more attractive. And I think it would be a really bad idea if it were to use __format__ (which I assume someone will suggest before this thread is over).
“Fixing” this is actually the worst option suggested yet:
it adds another formatting mini language that is not only incompatible, but also looks identical to the old one. Such a subtle difference would be very confusing
it doesn’t provide an unambiguous context independent migration path, i.e. pure linters that don’t do type analysis couldn’t suggest fixes.
it increases maintenance burden massively which is the primary cited reason against just asding the method alone.
In case anyone does not have such a long memory the str.format method was introduced in PEP 3103 which discusses the limitations of the % formatting method.
Agreed. As the origininal proposer, I’m strictly against extending the proposal to modify the formatting result of a %-placeholder in a potential new function. It would make the implementation more complicated and the transition less attractive for users as they are not guaranteed to have the same behavior. This would weaken the case I’m trying to make.
Instead, I would like to draw attention and get core dev feedback on the argument for formally discouraging the %-operator as written in the first half of %-style formatting method - #30 by timhoffm, which IMHO has not been responded to.
Premise: It would be a benefit to clearly state “do not use the %-formatting operator for new code” - This gives clear direction and makes the language better without breaking backward compatibility.
If we can do this right away, great let’s do it and not add anything new.
If not, the argument can only “people still want %-formatting in new code sometimes”. And then I argue they want it because of the %-placeholders, not because of the %-operator. A small and focussed addition of a .pformat() method would be a consistent alternative to the %-operator.
We could then write: “do not use the %-formatting operator for new code. In most cases you’ll want to use f-strings or the format() method instead. If you still want to use %-placeholder syntax, use the pformat() method instead.”