This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: string.format() should have a safe_substitute equivalent, to be run consecutively
Type: enhancement Stage: resolved
Components: Interpreter Core Versions: Python 3.7
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: azrdev, eric.smith, r.david.murray, steven.daprano
Priority: normal Keywords:

Created on 2015-07-01 20:42 by azrdev, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (6)
msg246047 - (view) Author: azrdev (azrdev) Date: 2015-07-01 20:42
"{1} {0}".format('one').format('two')

should return "two one", but throws

    IndexError: tuple index out of range


This would allow partial replacements, similar to string.Template.safe_substitute()
I suggest an analog construction (e.g. a method string.safe_format() )
msg246048 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-07-01 21:04
Why not use string.Template?
msg246054 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2015-07-02 02:25
So let's say your function would be named "safe_format". Then:

"{1} {0}".safe_format('one')

would give: "{1} one".

Then:

"{1} one".safe_format('two')

would be an error, because there's no index "1" in the args tuple.

I can't imagine how you'd implement this function so it would know to start with index 1 on the second call, instead of 0 as usual.

Or maybe it would decrement the index values it doesn't use, so that the result of the first call would be: "{0} one". That seems very complex, especially when you throw in implicit argument numbering, named arguments, format specifiers, etc.

I agree with David that string.Template might be better for you.

On an unrelated note, I think that "IndexError: tuple index out of range" is a horrible error message for this case. I wouldn't mind an enhancement request to make that something like "argument index '1' is out of range, only 1 argument supplied". Or something with better wordsmithing.
msg246055 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2015-07-02 02:31
I don't think that this behaviour is desirable, certainly not by default. If I write "{1} {0}".format('one') that's clearly a programming error and I should get an exception. Chaining a second .format method call afterwards does not make the first one any less of a mistake.

I think that there may be a good argument to be made for a safe_format with *named* arguments, like string.Template, but not positional arguments. But that would require some discussion, to decide on the correct behaviour. And why not use string.Template in the first place, or make the chained calls a single call?

"{1} {0}".format('one', 'two')

is clearly the most obvious way to do it. A slightly less obvious way:

"{{}} {}".format('one').format('two')
msg277607 - (view) Author: azrdev (azrdev) Date: 2016-09-28 11:24
(Sorry for not replying so long, I expected an email notification)

> Why not use string.Template?

because it's so slow

> I think that there may be a good argument to be made for a safe_format with *named* arguments, like string.Template, but not positional arguments.

Yes!

> But that would require some discussion, to decide on the correct behaviour.

What open question(s) do you think of?


For context, I got the idea for this from Qts .arg() which can be chained, see <https://doc.qt.io/qt-5/qstring.html#arg>.
msg277608 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2016-09-28 12:26
>> But that would require some discussion, to decide on the correct behaviour.

>What open question(s) do you think of?

You need to provide an exact specification of what you want. It's not clear, for example, if you want to support required positional placeholders ({0}, etc.) but optionally missing named placeholders ({foo}).

I'd also suggest implementing this as a function, so you can get some real-world usage out of it. Maybe:

def format_safe(s, *args, **kwargs):

format_safe("{0} {1} {foo} {bar}", 'one', 'two', bar='bar')
->
'one two {foo} bar}'

or whatever you decide the signature and functionality should be.

You can probably subclass from string.Formatter to do some of the heavy lifting for you, so I expect this wouldn't be very hard, depending on what you're really after.

While you might find this function useful, I don't want to get your hopes up that this would be added to core Python as a member of str. I still don't see why this would be better than a single call to .format() that specifies all of the parameters. You'd have to have some use case that doesn't involve chaining for that to make sense (to me). And maybe functools.partial() or some derivative would make sense in that case.
History
Date User Action Args
2022-04-11 14:58:18adminsetgithub: 68737
2017-03-07 18:45:38serhiy.storchakasetstatus: pending -> closed
resolution: rejected
stage: resolved
2016-09-28 12:26:34eric.smithsetstatus: open -> pending

messages: + msg277608
versions: + Python 3.7, - Python 3.6
2016-09-28 11:24:35azrdevsetmessages: + msg277607
2015-07-02 02:31:02steven.dapranosetnosy: + steven.daprano
messages: + msg246055
2015-07-02 02:25:29eric.smithsetversions: + Python 3.6
nosy: + eric.smith

messages: + msg246054

components: + Interpreter Core, - Library (Lib)
2015-07-01 21:04:55r.david.murraysetnosy: + r.david.murray
messages: + msg246048
2015-07-01 20:42:29azrdevcreate