Indexing cells in a table

Alex Martelli aleax at aleax.it
Sun Apr 28 04:57:54 EDT 2002


jb wrote:

> I have a base class x with attributes a,b,c,..., that is x.a=0 is o.k.
> 
> Now T is a rectangular table of elements of the type x, that is I can say
> T[4][3].c=1.
> 
> Is there a generic way to address an area of the table and assign values
> to one of the attributes in the area?
> That is, can I write a generic function setValue that works like
> 
> T.setValue( (0,0) ,(m,n) , c , 1 )

Almost -- it has to be something like:

T.setValues( (0,0), (m,n), 'c', 1)

Note the quotes around the 'c' -- you pass the attribute name as a
string.  Later I'll show a different syntax to avoid the quoting needs...

> and assigns the value 1 to the x.c-s in the specified area.
> 
> Example:
> 
>   setValue( (1,1), (2,3), c, 1)
> 
> is the same as
> 
>   T[1][1].c=1
>   T[1][2].c=1
>   ...
>   T[2][3].c=1

That would really be peculiar semantics in Python, where intervals
always follow the rule lower-bound-included, upper-bound-excluded
which helps so much in avoiding off-by-one errors.  I STRONGLY
suggest you to consider using (3,4) as the upperbounds to mean "go
to 3 excluded, and 4 excluded".

Anyway, using your semantics instead.  You could define the function
with method-syntax if and only if T is an instance of a class or type
that you control and whose sources you can modify.  Since the
function itself is clearly feasible by using only T's public interface 
(indeed that's how you define it!) I suggest you consider making the
function a normal, free-standing one instead.  Like this:

def setValues(T, (minI, minJ), (maxI, maxJ), attName, attValue):
    for i in range(minI, maxI+1):
        for j in range(minJ, maxJ+1):
            setattr(T[i][j], attName, attValue)

Note the awkware "+1" in the range calls -- this tells you there is
something peculiar about your semantics (to wit, you want upper
range included intervals).

This needs to be called as: setValues(T, (1,1), (2,3), 'c', 1).

Anyway, if T is e.g. an instance of a class you control, you can
just use this same def inside the class body and rename T to
self in the function to use your required syntax.

I would in fact suggest yet another small syntax variation -- call
this as: setValues(T, (1,1), (2,3), c=1)...:

def setValues(T, (minI, minJ), (maxI, maxJ), **attributes):
    for i in range(minI, maxI+1):
        for j in range(minJ, maxJ+1):
            for attName in attributes:
                attValue = attributes[attName]
                setattr(T[i][j], attName, attValue)

The "for attName in attributes:" is 2.2 syntax -- use instead
"in attributes.keys():" if you need portability to old Python versions.

Note that this latter syntax easily allows setting multiple attributes:
just call, e.g., setValues(T, (1,1), (2,3), a=12, b=34, c=56) should
you ever need that.  You pay little for the generality, and get a
rather pretty calling-syntax too.


Alex




More information about the Python-list mailing list