Steven D'Aprano said:
Errors should never pass silently, unless explicitly silenced. You have
implicitly silenced the TypeError you get from not having enough
arguments for the first format operation. That means that you will
introduce ambiguity and bugs.
"%i %i %i %i" % 5 % 3 %7
Here I have four slots and only three numbers. Which output did I
expect?
'%i 5 3 7'
'5 %i 3 7'
'5 3 %i 7'
'5 3 7 %i'
Or more likely, the three numbers is a mistake, there is supposed to be
a fourth number there somewhere, only now instead of the error being
caught immediately, it won't be discovered until much later.
You seem to have made an unwarranted assumption, namely that a binary
operator has to compile to a function with two operands. There is no
particular reason why this has to always be the case: for example, I
believe that C# when given several strings to add together optimises
this into a single call to a concatenation method.
[...]
Python *could* do something similar if the appropriate opcodes/methods
supported more than two arguments:
a+b+c+d might execute a.__add__(b,c,d) allowing more efficient string
concatenations or matrix operations, and a%b%c%d might execute as
a.__mod__(b,c,d).
That's only plausible if the operations are associative. Addition is
associative, but string interpolation is not:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
Since string interpolation isn't associative, your hypothetical __mod__
method might take multiple arguments, but it would have to deal with them
two at a time, unlike concatenation where the compiler could do them all
at once. So whether __mod__ takes two arguments or many is irrelevant:
its implementation must rely on some other function which takes two
arguments and must succeed or fail on that.
Either that, or we change the design of % interpolation, and allow it to
silently ignore errors. I assumed that is what Aaron wanted.
In that alternate universe your example:
"%i %i %i %i" % 5 % 3 %7
simply throws "TypeError: not enough arguments for format string"
That has a disturbing consequence.
Consider that most (all?) operations, we can use temporary values:
x = 1 + 2 + 3 + 4
=> x == 10
gives the same value for x as:
temp = 1 + 2 + 3
x = temp + 4
I would expect that the same should happen for % interpolation:
# using Aaron's hypothetical syntax
s = "%s.%s.%s.%s" % 1 % 2 % 3 % 4
=> "1.2.3.4"
should give the same result as:
temp = "%s.%s.%s.%s" % 1 % 2 % 3
s = temp % 4
But you're arguing that the first version should succeed and the second
version, using a temporary value, should fail. And that implies that if
you group part of the expression in parentheses, it will fail as well:
s = ("%s.%s.%s.%s" % 1 % 2 % 3) % 4
Remove the parentheses, and it succeeds. That's disturbing. That makes
the % operator behave very differently from other operators.
Note that with the current syntax, we don't have that problem: short-
supplying arguments leads to an exception no matter what.
"%s" % (1,2,3)
just converts the tuple as a single argument. It also provides the
answer to how you put a percent in the format string (double it)
I trust you know that already works, but just in case:
'12.5%'
and what happens if a substitution inserts a percent (it doesn't
interact with the formatting operators).
Ditto:
'%g'