[Python-3000] string.Formatter class

Eric Smith eric+python-dev at trueblade.com
Tue Aug 28 13:48:24 CEST 2007


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.
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).
Given these, we can define a formatter that uses the normal syntax, but 
calls its arguments to get their value:
=================
class CallFormatter(Formatter):
 def format_field(self, value, format_spec):
 return format(value(), format_spec)
fmt = CallFormatter()
print(fmt.format('*{0}*', datetime.datetime.now))
=================
which prints:
*2007年08月28日 07:39:29.946909*
Or, something that uses vertical bars for separating markup:
=================
class BarFormatter(Formatter):
 # returns an iterable that contains tuples of the form:
 # (literal_text, field_name, format_spec, conversion)
 def parse(self, format_string):
 for field in format_string.split('|'):
 if field[0] == '+':
		# it's markup
 field_name, _, format_spec = field[1:].partition(':')
 yield None, field_name, format_spec, None
 else:
 yield field, None, None, None
fmt = BarFormatter()
print(fmt.format('*|+0:^10s|*', 'foo'))
=================
which prints:
* foo *
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
These are obviously contrived examples, without great error checking, 
but I think they demonstrate the flexibility. I'm not wild about the 
method names, so any suggestions are appreciated. Any other comments 
are welcome, too.
Eric.


More information about the Python-3000 mailing list

AltStyle によって変換されたページ (->オリジナル) /