A Moronicity of Guido van Rossum

Michael ms at cerenity.org
Sun Oct 2 18:33:13 EDT 2005


Fredrik Lundh wrote:
...
> fwiw, they've also been around for ages:
> 
>     http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?list+comprehension
> 
> (the name goes back to the early eighties, the construct is older than
> that)

Ahh... Fair enough. I hadn't come across it as a programming construct until
I hit Python. I'd seen the (presumable) precursor of set comprehension it in
maths & formal methods before though.

To help Xah along, this shows a //more nearly// correct version of his table
function (his doesn't do anything like the spec). It works correctly for
tables of the form:

table("i", ("i",3))
table("i,j", ("i",3), ("j",3))
table("math.cos(i+j)", ("i",3), ("j",-3,3))

It doesn't produce quite the right structure when you have more than
2 iteration rules). 

Problems with this implementation:
   * mkrange() is not passed along the existing context.
     This means tables of the form:
        table("i,j", ("i",3), ("j",1,"i"))

     Won't work. This would require changing the mkRange function such
     that it's passed the most currently built environment. This is a
     relatively trivial change, which I'll leave for Xah.

   * The structure is incorrect for more than 2 iteration rules. I think
     I'm missing a simple/obvious trick in my mkTable._extend_table
     function.
     I'm not really fussed though. (It's clearly something dumb :)

   * It's not really clear which list nests which. It's possible the lists
     are nested the wrong way round.

I'm fairly certain that the evalTable code will work fine when the mkTable
code creates the right structure.

I'll leave that to Xah to fix. It's somewhat further along than his
original attempt though. (actually matches his spec for 1 or 2 iteration
rules).

def mkRange(listspec):
    if len(listspec)==2:
        return xrange(1,listspec[1]+1)
    elif len(listspec)==3:
        return xrange(listspec[1],listspec[2]+1)
    return []

def mkTable(ignore, *listspecs):
    def _extend_table(listspecs, result):
        if len(listspecs) == 0:
            return result
        else:
            listspec = listspecs[-1]
            listspecs = listspecs[:-1]
            r2 = []
            for R_ in result:
                 for R in R_: # SMELLY
                    inner_result = []
                    for i in mkRange(listspec):
                        inner_env2 = dict(R[1])
                        inner_env2[listspec[0]] = i
                        inner_result.append( (ignore, inner_env2) )
                    r2.append(inner_result)
            result = _extend_table(listspecs, r2)
        return result
    return _extend_table(listspecs, 
                         [[(ignore,dict(globals()))]]) # SMELLY

def evalTable(table):
    if len(table) ==0:
        return table
    else:
        result = []
        for evallist in table:
            inner_result = []
            for eval_args in evallist:
              try:
                r = eval(*eval_args)
                inner_result.append(r)
              except TypeError:
                inner_result.append(evalTable(eval_args))
            result.append(inner_result)
        return result

def table(ignore, *listspecs):
    abstract_table = mkTable(ignore, *listspecs)
    return evalTable(abstract_table)

Example:

>>> import math
>>> table("math.cos(i+j)", ("i",3), ("j",-3,3))
[[-0.41614683654714241, 0.54030230586813977, 1.0], [0.54030230586813977,
1.0, 0.54030230586813977], [1.0, 0.54030230586813977,
-0.41614683654714241], [0.54030230586813977, -0.41614683654714241,
-0.98999249660044542], [-0.41614683654714241, -0.98999249660044542,
-0.65364362086361194], [-0.98999249660044542, -0.65364362086361194,
0.28366218546322625], [-0.65364362086361194, 0.28366218546322625,
0.96017028665036597]]

Regards,


Michael.




More information about the Python-list mailing list