switch recipe?

Mark McEahern marklists at mceahern.com
Fri Jul 12 18:45:27 EDT 2002


[Tim Peters]
> The top one generates an unbounded sequence, due to the "while True".  The
> Icon language calls this "repeated alternation", and actually has a prefix
> operator for it (the vertical bar).
>
> What I'm unclear about is why we're writing a function to return
> a generator function:  why not write a generator function directly?

Well dang, my original motivation was so I could pass around the generator
without specifying the args.  As you point out, that's completely
unnecessary.  Thanks!

> So my candidate for simplification is:
>
> def make_switch(*args):
>     """Generate the elements in args repeatedly."""
>     if not args:
>         raise TypeError("at least one argument required")
>     while True:
>         for a in args:
>             yield a
>
> I'd lose the "if not args:" block, though; if the arglist is
> empty, it will
> simply terminate without yielding anything, and that's what I expect the
> empty case to do.

If you leave the while True, then it won't raise StopIteration when you call
it without arguments.  The simple fix is to replace that with while args.
Here's the result of my latest tinkering.  For what it's worth, I think I
prefer raising the error in the generator when args is not specified rather
than waiting until next() is called the first time--on the principle that
raising the error earlier is better.  Still, this version shows the delayed
raise....

#! /usr/bin/env python

from __future__ import generators
import unittest

def repeat(*args):
    """Return an unbounded iterator that repeatedly iterates over args."""
    while args:
        for a in args:
            yield a

def weave(values, repeat, weaver):
    for item in values:
        yield weaver(item, repeat.next())

def color_item(item, color):
    template = "<%(color)s>%(item)s</%(color)s>"
    return template % locals()

class test(unittest.TestCase):

    def test(self):
        values = range(10)
        colors = ("red", "organge", "yellow", "green", "blue", "indigo",
                  "violet")
        repeat_colors = repeat(*colors)
        expected = ['<red>0</red>',
                    '<organge>1</organge>',
                    '<yellow>2</yellow>',
                    '<green>3</green>',
                    '<blue>4</blue>',
                    '<indigo>5</indigo>',
                    '<violet>6</violet>',
                    '<red>7</red>',
                    '<organge>8</organge>',
                    '<yellow>9</yellow>']
        generated = [x for x in weave(values, repeat_colors, color_item)]
        self.assertEquals(expected, generated)

    def test_empty(self):
        r = repeat()
        self.assertRaises(StopIteration, r.next)

if __name__ == "__main__":
    unittest.main()

-






More information about the Python-list mailing list