[Python-3000] More PEP 3101 changes incoming

Ron Adam rrr at ronadam.com
Tue Aug 14 01:52:31 CEST 2007



Talin wrote:

> I'm not sure that I'm happy with my own syntax proposal just yet. I want 
> to sit down with Guido and talk it over before I commit to anything.
> 
> I think part of the difficulty that I am having is as follows:

> However, the old syntax doesn't fit very well with the new requirements: 
> the desire to have the 'repr' option take precedence over the 
> type-specific formatter, and the desire to split the format specifier 
> into two parts, one which is handled by the type-specific formatter, and 
> one which is handled by the general formatter.

> But with these format strings, it seems (to me, anyway) that the design 
> choices are a lot more arbitrary and driven by aesthetics. Almost any 
> combination of specifiers will work, the question is how to arrange them 
> in a way that is easy to memorize.

They seem arbitrary because intuition says to put things together that 
"look" like they belong together, but the may really be two different 
things. Or because we try to use one thing for two different purposes. 
This is also what makes it hard to understand as well.

I reconsidered the split term forms a bit more and I think I've come up
with a better way to think about them. Sometimes a slight conceptual shift
can make a difference.

The basic form is:

       {name[:][type][alignment_term][,content_modifying_term]}


TYPE:	
	The specifier type.  One of 'deifsrx'.
                (and any others I left off)

         No type defaults to 's'
                (this is the safest default, but it could
                 be more flexible if need be.)


ALIGNMENT TERM:   [direction]width[/fill]

     direction:    is one of   '<^>'
     width:        a positive integer
     /fill:         a character

     * This pattern is always the same and makes up an alignment term.
       By keeping this part consistant, it makes it easy to remember
       and understand.


CONTENT MODIFYING TERMS:

* Strings and numbers are handled differently, You would never use both of 
these at the same time.

     STRINGS:  [string_width]

         string_width:    Positive or negative integer to clip a
                          long string.

         * works like slice, s[:n] or s[-n:])


     NUMBERS:   [sign][0][digits][.decimals][%]

	sign:       '-', '+', '(', ' ', ''
                     * The trailing ')' is optional.

         0:	    use leading zeros

         digits:     number of digits, or number before decimal.

         .decimal:   number of decimal places

         %:          multiplies by 100 and add ' %' to end.



Some differences are, alignment terms never have '+-' in them, or any of 
the number formatting symbols.  They are consistent.

The digits value are number of digits before the decimal.  This doesn't 
include the other symbols used in the field so it isn't the same as a field 
width.

    (I believe this is one of the points of confusion.  Or it is for me.)

It bothered me that to figure out the number of digits before the decimal I 
had to subtract all the other parts.  You can think of this as shorter form 
of the # syntax.

       ######.###  ->  6.3



Surprisingly this does not have a big impact on the latest proposed syntax 
or the number of characters used unless someone wants to both specify a 
numeric formatting term with a larger sized alignment term.

So here's what how it compares with an actual doctest that passes.

Note: fstr() and ffloat() are versions of str and float with the needed 
methods to work.

Examples from python3000 list:
     (With only a few changes where it makes sense or to make it work.)

     >>> floatvalue = ffloat(123.456)

     :f        # Floating point number of natural width
     >>> fstr('{0:f}').format(floatvalue)
     '123.456'

     :f10      # Floating point number, width at least 10
               ## behavior changed
     >>> fstr('{0:f10}').format(floatvalue)
     '       123.456'

     >>> fstr('{0:f>10}').format(floatvalue)
     '   123.456'

     :f010     # Floating point number, width at least 10, leading zeros
     >>> fstr('{0:f010}').format(floatvalue)
     '0000000123.456'

     :f.2      # Floating point number with two decimal digits
     >>> fstr('{0:f.2}').format(floatvalue)
     '123.46'

     :8        # Minimum width 8, type defaults to natural type
               ## defualt is string type, no type is guessed.
     >>> fstr('{0:8}').format(floatvalue)
     '123.456 '

     :d+2      # Integer number, 2 digits, sign always shown
               ## (minor change to show padded digits.)
     >>> fstr('{0:d+5}').format(floatvalue)
     '+  123'

     :!r       # repr() format
               ## ALTERED, not special case syntax.
               ## the 'r' is special even so.
     >>> fstr('{0:r}').format(floatvalue)
     '123.456'

     :10!r     # Field width 10, repr() format
               ## ALTERED, see above.
     >>> fstr('{0:r10}').format(floatvalue)
     '123.456   '


     :s10      # String right-aligned within field of minimum width
               # of 10 chars.
     >>> fstr('{0:s10}').format(floatvalue)
     '123.456   '


     :s10.10   # String right-aligned within field of minimum width
               # of 10 chars, maximum width 10.
               ## ALTERED, comma instead of period.
     >>> fstr('{0:s10,10}').format(floatvalue)
     '123.456   '

     :s<10     # String left-aligned in 10 char (min) field.
     >>> fstr('{0:s<10}').format(floatvalue)
     '123.456   '

     :d^15     # Integer centered in 15 character field
     >>> fstr('{0:d^15}').format(floatvalue)
     '      123      '

     :>15/.    # Right align and pad with '.' chars
     >>> fstr('{0:>15/.}').format(floatvalue)
     '........123.456'

     :f<+015.5 # Floating point, left aligned, always show sign,
               # leading zeros, field width 15 (min), 5 decimal places.
               ## ALTERED: '<' not needed, size of digits reduced.
     >>> fstr('{0:f010.5}').format(floatvalue)
     '0000000123.45600'


So very little actually changed in most of these syntax wise.  Some 
behavioral changes to number formatting. But I think these are plus's.

  - I haven't special cases the '!' syntax.

  - The behavior of digits in the numeric format term is changed.


So if the terms have the following patterns they can easily be identified.

     <dirction> <number> </char>    alignment term

     <sign> <number>      With strings type only ... A clipping term

     <sign> <0> <digits> <.> <decimals> <%>   A numeric format term



And example of using these together...

     s>25,-25            right align short strings,
                         clip long strings from the end.
                         (clips the beginning off  s = s[-25:])


     f^30/_,(010.3%)     Centers a zero padded number with 3 decimal,
                         and with parentheses around negative numbers,
                         and spaces around positive numbers,
                         in a field 30 characters wide,
                         with underscore padding.

Yes, this example is a bit long, but it does a lot!



> Guido's been suggesting that I model the format specifiers after the 
> .Net numeric formatting strings, but this system is significantly less 
> capable than %-style format specifiers. Yes, you can do fancy things 
> like "(###)###-####", but there's no provision for centering or for a 
> custom fill character.

Usually when you use this type of formatting it's very specific and doesn't 
need any sort of aligning.  Maybe we can try to add this in later after the 
rest is figured out and working?  It would fit naturally as an alternative 
content modifying term for strings.

       s^30,(###)###-####   Center phone numbers in a 30 character column.

The numbers signs are enough to identify the type here.


> This would be easier if I was sitting in a room with other Python 
> programmers so that I could show them various suggestions and see what 
> their emotional reactions are. I'm having a hard time doing this in 
> isolation. That's kind of why I want to meet with Guido on this, as he's 
> good at cutting through this kind of crap.

I agree, it would be easier.

Cheers,
    Ron




More information about the Python-3000 mailing list