using generators with format strings
Peter Otten
__peter__ at web.de
Thu Jul 22 08:44:11 EDT 2004
Hans Nowak wrote:
> def format_with_generator(formatstr, gen):
> arguments = []
> while 1:
> try:
> s = formatstr % tuple(arguments)
> except TypeError, e:
> if e.args[0] == 'not enough arguments for format string':
> item = gen.next()
> arguments.append(item)
> else:
> raise
> else:
> return s
Nice. You led me to dump the regexp approach...
Here's a variant that avoids the guessing for all but the first occurence of
a format and tries to get the tuple length right on the first pass of the
while loop:
<code>
def firstN(seq, n):
next = iter(seq).next
return [next() for _ in xrange(n)]
def _provoke_error_message():
try:
"%s" % ()
except TypeError, e:
return e.args[0]
else:
raise Exception("cannot cope with severe change "
"in format string behaviour")
class format(object):
""" Formatter that accepts a sequence instead of a tuple
and ignores superfluous items in that sequence.
XXX StopIteration should be morphed into ValueError.
XXX No test suite. Use at your own risk.
"""
_message = _provoke_error_message()
_cache = {}
def __new__(cls, fmt):
cache = cls._cache
if fmt in cache:
return cache[fmt]
else:
cache[fmt] = obj = object.__new__(cls)
obj._cnt = None
obj._fmt = fmt
return obj
def __mod__(self, seq):
if self._cnt is not None:
if __debug__: print "we know it (%s)" % self._cnt # remove
return self._fmt % tuple(firstN(seq, self._cnt))
return self._guess(seq)
def _guess(self, seq):
if __debug__: print "guessing (%r)" % self._fmt # remove
it = iter(seq)
fmt = self._fmt
cnt = fmt.count("%") - fmt.count("%%")
args = tuple(firstN(it, cnt))
while 1:
try:
result = fmt % args
except TypeError, e:
if e.args[0] == self._message:
args += (it.next(),)
cnt += 1
if __debug__: print "one more (%s)" % cnt # remove
else:
raise
else:
self._cnt = cnt
return result
if __name__ == "__main__":
print format("%s") % (1,2,3)
print format("%s %-*s %*.*f%% %*f %0*d") % ((1,2,3) + (5,)*100)
print format("%s %-*s %*.*f%% %*f %0*d") % ((1,2,3) + (5,)*100)
print format("%s") % ("so what",)
</code>
More information about the Python-list
mailing list