[Python-3000] More PEP 3101 changes incoming

Eric V. Smith eric+python-dev at trueblade.com
Sat Aug 11 05:30:33 CEST 2007


Greg Ewing wrote:
> Eric Smith wrote:
>> 1: "".format() ... understands which 
>> types can be converted to other types, and does the conversions.
>>
>> 2: each type's __format__ function understands how to convert to some 
>> subset of all types (int can convert to float and decimal, for example).
>>
>> The problem with approach 2 is that there's logic in 
>> int.__format__() that understands float.__format__() specifiers, and 
>> vice-versa.  At least with approach 1, all of this logic is in one place.
> 
> Whereas the problem with approach 1 is that it's not
> extensible. You can't add new types with new format
> specifiers that can be interconverted.

Granted.

> I don't think the logic needs to be complicated. As
> long as the format spec syntaxes are chosen sensibly,
> it's not necessary for e.g. int.__format__ to be able
> to parse float's format specs, only to recognise when
> it's got one. That could be as simple as
> 
>    if spec[:1] in 'efg':
>      return float(self).__format__(spec)

Right.  Your "if" test is my is_float_specifier function.  The problem 
is that this needs to be shared between int and float and string, and 
anything else (maybe decimal?) that can be converted to a float.  Maybe 
we should make is_float_specifier a classmethod of float[1], so that 
int's __format__ (and also string's __format__) could say:

if float.is_float_specifier(spec):
    return float(self).__format__(spec)

And float's __format__ function could do all of the specifier testing, 
for types it knows to convert itself to, and then say:

if not float.is_float_specifier(spec):
     return NotImplemented
else:
     # do the actual formatting

And then presumably the top-level "".format() could check for 
NotImplemented and convert the value to a string and use the specifier 
on that:

result = value.__format__(spec)
if result is NotImplemented:
    return str(value).__format__(spec)
else:
    return result

Then we could take my approach number 1 above, but have the code that 
does the specifier testing be centralized.  I agree that central to all 
of this is choosing specifiers sensibly, for those types that we expect 
to supply interconversions (great word!).

For types that won't be participating in any conversions, such as date 
or user defined types, no such sensible specifiers are needed.

> Another advantage of letting the __format__ methods
> handle it is that a given type *can* handle another
> type's format spec itself if it wants. E.g. if float
> has some way of handling the 'd' format that's
> considered better than converting to int first, then
> it can do that.

But then float's int formatting code would have to fully implement the 
int formatter.  You couldn't add functionality to the int formatter (and 
its specifiers) without updating the code in 2 places: both int and float.

Eric.

[1]: If we make it a class method, it could just be is_specifier(), or 
maybe __is_specifier__.  This name would be implemented by all types 
that participate in the interconversions we're describing.


More information about the Python-3000 mailing list