[Python-3000] string.Formatter class

Ron Adam rrr at ronadam.com
Thu Aug 30 13:12:13 CEST 2007



Eric Smith wrote:
> One of the things that PEP 3101 deliberately under specifies is the 
> Formatter class, leaving decisions up to the implementation.  Now that a 
> working implementation exists, I think it's reasonable to tighten it up.
> 
> I have checked in a Formatter class that specifies the following methods 
> (in addition to the ones already defined in the PEP):
> 
> parse(format_string)
> Loops over the format_string and returns an iterable of tuples 
> (literal_text, field_name, format_spec, conversion).  This is used by 
> vformat to break the string in to either literal text, or fields that 
> need expanding.  If literal_text is None, then expand (field_name, 
> format_spec, conversion) and append it to the output.  If literal_text 
> is not None, append it to the output.
> 
> get_field(field_name, args, kwargs, used_args)
> Given a field_name as returned by parse, convert it to an object to be 
> formatted.  The default version takes strings of the form defined in the 
> PEP, such as "0[name]" or "label.title".  It records which args have 
> been used in used_args.  args and kwargs are as passed in to vformat.

Rather than pass the used_args set out and have it modified in a different 
methods, I think it would be better to pass the arg_used back along with 
the object.  That keeps all the code that is involved in checking used args 
is in one method.  The arg_used value may be useful in other ways as well.

      obj, arg_used = self.get_field(field_name, args, kwargs)
      used_args.add(arg_used)


> convert_field(value, conversion)
> Converts the value (returned by get_field) using the conversion 
> (returned by the parse tuple).  The default version understands 'r' 
> (repr) and 's' (str).


> Or, define your own conversion character:
> =================
> class XFormatter(Formatter):
>      def convert_field(self, value, conversion):
>          if conversion == 'x':
>              return None
>          if conversion == 'r':
>              return repr(value)
>          if conversion == 's':
>              return str(value)
>          return value
> fmt = XFormatter()
> print(fmt.format("{0!r}:{0!x}", fmt))
> =================
> which prints:
> <__main__.XFormatter object at 0xf6f6d2cc>:None

I wonder if this is splitting things up a bit too finely?  If the format 
function takes a conversion argument, it makes it possible to do everything 
by overriding format_field.

     def format_field(self, value, format_spec, conversion):
         return format(value, format_spec, conversion)


Adding this to Talins suggestion, the signature of format could be...

     format(value, format_spec="", conversion="")


Then the above example becomes...

   class XFormatter(Formatter):
      def format_field(self, value, format_spec, conversion):
          if conversion == 'x':
              return "None"
          return format(value, format_spec, conversion)


It just seems cleaner to me.

Cheers,
    Ron






More information about the Python-3000 mailing list