New Python 3.0 string formatting - really necessary?

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sun Dec 21 08:52:27 EST 2008


On Sun, 21 Dec 2008 12:45:32 +0000, Duncan Booth wrote:

> Steven D'Aprano <steve at REMOVE-THIS-cybersource.com.au> wrote:
> 
>> 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:

>>> "%%%s" % ("%s" % "b")
'%b'
>>> ("%%%s" % "%s") % "b"
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:

>>> "%g%%" % 12.5
'12.5%'

> and what happens if a substitution inserts a percent (it doesn't
> interact with the formatting operators).

Ditto:

>>> "%s" % "%g"
'%g'



-- 
Steven



More information about the Python-list mailing list