Re: using generators with format strings

Discussion in 'Python' started by Guest, Jul 21, 2004.

  1. Guest

    Guest Guest

    List comprehension is a beautiful thing.

    x = "Hello, %s, this is a %s with %s and %s on top of %s" %
    tuple([myvalues() for i in xrange(5)])

    You could even make the xrange argument dependent upon the
    number of "%s" in the string.

    ---- Original message ----
    >Date: Wed, 21 Jul 2004 15:21:50 -0500
    >From: marduk <>
    >Subject: using generators with format strings
    >To:
    >
    >I have a weird request.
    >
    >I want to be able to say
    >
    >def myvalues():
    > while True:
    > # stuff that determines a new somevalue
    > yield somevalue
    >
    >x = "Hello, %s, this is a %s with %s and %s on top of %s" %

    myvalues()
    >y = "Yes it's true that %s has way too many %s's" % myvalues()
    >
    >I was hoping that myvalues() would be iterated over, but

    instead the
    >interpreter gives me a "TypeError: not enough arguments for

    format string"
    >error. I tried tuple(myvalues()) and I think that kinda

    works but of
    >course myvalues goes into an infinite loop. myvalues will not

    know before
    >hand how many times it will be called.
    >
    >Is there actually a simple way of doing this that I'm

    overlooking?
    >
    >
    >
    >----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure

    Usenet News==----
    >http://www.newsfeed.com The #1 Newsgroup Service in the

    World! >100,000 Newsgroups
    >---= 19 East/West-Coast Specialized Servers - Total Privacy

    via Encryption =---
    >--
    >http://mail.python.org/mailman/listinfo/python-list
     
    Guest, Jul 21, 2004
    #1
    1. Advertising

  2. Guest

    marduk Guest

    On Wed, 21 Jul 2004 16:38:55 -0400, brianc wrote:

    > List comprehension is a beautiful thing.
    >
    > x = "Hello, %s, this is a %s with %s and %s on top of %s" %
    > tuple([myvalues() for i in xrange(5)])
    >
    > You could even make the xrange argument dependent upon the
    > number of "%s" in the string.


    Well, that has two problems:

    a) the tuple is a list of generators of strings, not strings
    b) I was hoping I would not have to count all the "%s"s in the string




    ----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
    http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
    ---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
     
    marduk, Jul 21, 2004
    #2
    1. Advertising

  3. Guest

    Hans Nowak Guest

    marduk wrote:
    > On Wed, 21 Jul 2004 16:38:55 -0400, brianc wrote:
    >
    >
    >>List comprehension is a beautiful thing.
    >>
    >>x = "Hello, %s, this is a %s with %s and %s on top of %s" %
    >>tuple([myvalues() for i in xrange(5)])
    >>
    >>You could even make the xrange argument dependent upon the
    >>number of "%s" in the string.

    >
    >
    > Well, that has two problems:
    >
    > a) the tuple is a list of generators of strings, not strings
    > b) I was hoping I would not have to count all the "%s"s in the string


    An interesting problem. Apparently the % string interpolation operator checks
    the length of the tuple, so you cannot use an object (generator or otherwise)
    to generate/pass values "on demand". So a different approach is in order. The
    following code seems to work, although I wouldn't recommend it for production code:

    --->8---
    def integers(n):
    while 1:
    yield n
    n = n + 1

    i = integers(0)

    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

    fs = "Gimme a %s and a %s and a %s!"
    print format_with_generator(fs, i)
    print format_with_generator(fs, i)
    --->8---

    Hope this helps!

    --
    Hans Nowak ()
    http://zephyrfalcon.org/
     
    Hans Nowak, Jul 22, 2004
    #3
  4. Guest

    Peter Otten Guest

    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>
     
    Peter Otten, Jul 22, 2004
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Francis Avila
    Replies:
    0
    Views:
    479
    Francis Avila
    Nov 2, 2003
  2. The_Incubator
    Replies:
    4
    Views:
    439
    Linus Elman
    Jan 6, 2004
  3. fishboy
    Replies:
    0
    Views:
    373
    fishboy
    May 31, 2004
  4. marduk
    Replies:
    7
    Views:
    349
    Bengt Richter
    Jul 27, 2004
  5. Ben

    Strings, Strings and Damned Strings

    Ben, Jun 22, 2006, in forum: C Programming
    Replies:
    14
    Views:
    789
    Malcolm
    Jun 24, 2006
Loading...

Share This Page