The LOOP macro

T. Ogawa hydroxide at inorbit.com
Mon Mar 22 21:02:36 EST 2004


(xposted to c.l.python)

Here is a partial implementation/proof of concept for Python... the
remainder is left as an exercise ;-).  Working examples based on some
of the lisp examples previously posted are below.  It doesn't use
anything particularly tricky (ie: no exec/eval/__metaclass__/__new__).
 Using it is, of course, clumsier than loop for short examples where a
listcomp makes more sense, but apparently not really so for longer
ones...

[Use, share, enjoy - all at your own risk.  Do not run nuclear
reactors or medical equipment using it]

###################################### BEGIN loop.py
class Loop(list):
    class Max(object):
        def __cmp__(self, other):
            return 1

    def fix(self, item, key, default):
        if item is None:
            item = self.curr
        return item, self.d.get(key, default)
        
    def collect(self, *args,**kwds):
        try:
            key = kwds["key"]
            item = self.curr
        except KeyError:
            try:
                key, item = args
            except ValueError:
                key = "_"
                try:
                    item = args[0]
                except IndexError:
                    item = None
            
        item, val = self.fix(item, key, [])
        val.append(item)
        self.d[key] = val
        
    def summing(self, key, item=None):
        item, val = self.fix(item, key, 0)
        self.d[key] = val + item

    def minimizing(self, key, item=None):
        item, val = self.fix(item, key, self.Max())
        self.d[key] = min(val, item)

    def maximizing(self, key, item=None):
        item, val = self.fix(item, key, None)
        self.d[key] = max(val, item)

    def counting(self, key, item=None):
        self.summing(key, 1)

    def final(self):
        key = self.d.keys()[0]
        return self.d[key]

    def __init__(self, mylist):
        self.d = {}
        for elem in mylist:
            self.curr = elem
            self.each()
        final = self.final()
        if isinstance(final, str):
            self.append(final)
        else:
            try:
                self.extend(final)
            except TypeError:
                self.append(final)
    
    def __getattr__(self, attr):
        if attr in self.d:
            return self.d[attr]
        return []
    
###################################### END loop.py

from random import random as rand

# Rob Warnock no.1
#
# def listcomp_js(mystrings):
#     ", ".join(["'%s'"%word.replace("'", "''") for word in
mystrings])

class FixQuotes(Loop):
    class Escape(Loop):
        def each(self):
            self.collect()
            if self.curr == "'":
                self.collect()

        def final(self):
            return "".join(self._)
        
    def each(self):
        self.collect("'%s'" % self.Escape(self.curr)[0])


def join_strings(mystrings):
    return ", ".join(FixQuotes(mystrings))

x = ["Here", "is", "Bob's", "house", "and", "Charles'"]
print join_strings(x)
print


# Peter Siebel no. 1
#
# print [rand() for i in range(10)]

class MyLoop(Loop):
    def each(self):
        self.collect(rand())
print MyLoop(range(10))
print


# Peter Siebel no. 2
class MyLoop(Loop):
    def each(self):
        self.minimizing("mymin")
        self.maximizing("mymax")
        self.summing("mysum")
        self.counting("mylen")

    def final(self):
        return self.mymin, self.mymax, self.mysum/float(self.mylen)
print MyLoop(range(100))
print


# Widget setup for the next examples
class Widget(object):
    def __init__(self):
        if rand() > 0.5:
            self.is_good = True
            self.colour = "red"
            self.is_foo = True
            self.is_bar = False
        else:
            self.is_bar = True
            self.is_good = False
            self.colour = "blue"
            if rand() > 0.5:
                self.is_foo = True
            else:
                self.is_foo = False
widgets = [Widget() for i in range(10)]


# Peter Siebel no. 3
#
# print [w for w in widgets if w.is_good]

class MyLoop(Loop):
    def each(self):
        widget = self.curr
        if widget.is_good:
            self.collect(widget)
print MyLoop(widgets)
print


# Peter Siebel no. 4
class MyLoop(Loop):
    def each(self):
        widget = self.curr
        if widget.colour == "red":
            self.counting("red")
        elif widget.colour == "blue":
            self.counting("blue")
        self.counting("total")

    def final(self):
        return self.red, self.blue, self.total
print MyLoop(widgets)
print


# Peter Siebel no. 5b
class MyLoop(Loop):
    def each(self):
        widget = self.curr
        is_foo = widget.is_foo
        is_bar = widget.is_bar 
        if is_foo:
            self.collect(key="foos")
        if is_bar:
            self.collect(key="bars")
        if is_foo and is_bar:
            self.collect(key="both")

    def final(self):
        return self.foos, self.bars, self.both

for widgetset in MyLoop(widgets):
    print widgetset



More information about the Python-list mailing list