[Python-3000] More PEP 3101 changes incoming
Carl Johnson
carlmj at hawaii.edu
Mon Aug 13 12:08:50 CEST 2007
(First, let me apologize for diving into a bike shed discussion.)
There are two proposed ways to handle custom __format__ methods:
> class MyInt:
> def __format__(self, spec):
> if int.is_int_specifier(spec):
> return int(self).__format__(spec)
> return "MyInt instance with custom specifier " + spec
> def __int__(self):
> return <some local state>
and
> class MyInt:
> def __format__(self, spec):
> if is_custom_spec(spec):
> return "MyInt instance with custom specifier " + spec
> return NotImplemented
> def __int__(self):
> return <some local state>
I think this would be more straightforward as:
class MyInt:
def __format__(self, spec):
if is_MyInt_specific_spec(spec):
return "MyInt instance with custom specifier " + spec
else:
return int(self).__format__(spec)
def __int__(self):
return <some local state>
The makers of the MyInt class should be the ones responsible for
knowing that
MyInt can be converted to int as needed for output. If they want
MyInt to
handle all the same format spec options as MyInt, it's up to them to
either
implement them all in their __format__ or to cast the instance object
to int
then call its __format__ object by themselves. I don't see the point
in having
format guess what MyInt should be converted to if it can't handle the
options
passed to it. If we go too far down this road, if MyInt craps out
when given
":MM-DD-YY", then format will be obliged to try casting to Date just
to see if
it will work. No, I think the format function should be somewhat
dumb, since
dumb makes more sense to __format__ implementers than clever. Let
them figure
out what their type can be cast into.
In the case that regular int can't handle the given format spec either,
int.__format__ will raise (return?) NotImplemented, in which case the
format
function will try string conversion, and then if that also pukes, a
runtime
exception should be raised.
I also like the idea of using "!r" for calling repr and agree that it
should be
listed first. The syntax seems to be calling out for a little bit of
extension
though. Might it be nice to be able to do something like this?
s = "10"
print("{0!i:+d}".format(s)) #prints "+10"
The !i attempts to cast the string to int. If it fails, then an
exception is
raised. If it succeeds, then the int.__format__ method is used on the
remainder
of the spec string. The logic is that ! commands are abbreviated
functions that
are applied to the input before other formatting options are given.
On the one hand, this does risk a descent into "line noise" if too
many !
options are provided. On the other hand, I think that providing !
options for
just repr, str, int, and float probably wouldn't be too bad, and
might save
some tedious writing of int(s), etc. in spots. It seems like if we're
going to
have a weird syntax for repr anyway, we might as well use it to make
things
more convenient in other ways. Or is this too TMTOWTDI-ish, since one
could
just write int(s) instead? (But by that logic, one could write repr
(s) too…)
The format function would end up looking like this:
def format(obj, spec):
if spec[0] == "!":
switch statement for applying obj = repr(obj), obj = int
(obj), etc.
spec = spec[2:]
if obj.__format__ and type(obj) is not str:
try:
#if spec contains letters not understood, __format__
raises NI
return obj.__format__(spec)
except NotImplemented:
pass #everything gets put through str as a last resort
return str(obj).__format__(spec) #last chance before throwing
exception
Does this make sense to anyone else?
--Carl Johnson
More information about the Python-3000
mailing list