[Tutor] class Clowning: saving references to other instances
Rob McGee
i812@iname.com
Sat, 15 Dec 2001 01:38:25 -0600
Okay, here's what I have: a class of objects placed on a grid referenced
with X, Y coordinates. Need an example? Here:
{code}
from string import uppercase # letters A to Z
class Clown:
def __init__(self, location, index, gridSize=16, uppercase=uppercase):
self.location = location # an integer, unique
self.index = index # also unique integer
self.name = uppercase[index] # uppercase letter, also unique
self.coord = divmod(location, gridSize) # X, Y tuple
def __str__(self):
return self.name
... and so on
import random
def makeClowns(numClowns=16, gridSize=16):
gridAvail = range(gridSize**2) # default grid of 256
clowns = []
for index in range(numClowns):
# select a random number from gridAvail and remove it from the list
location = gridAvail.pop(random.randrange(len(gridAvail)))
clown = Clown(location, index) # create instance
clowns.append(clown) # save it in a list
return clowns # return list of Clowns
clowns = makeClowns()
{/code}
(Those of you who remember my prior posts may notice that I've taken
some of your suggestions. :)
*** the problem ***
There are other methods, including one which calculates the distance
from one Clown instance to another. The distance(self, other) method
uses "exec" to store the distance values in self.(other.name) and in
other.(self.name) (such as "self.A" and "other.Z" for the distance
between the instances named A and Z.) Because it's tied to the way I'm
storing these instances, I don't like the way it works -- if I change
how the data is stored I'll also have to change the class method.
The reason why I'm doing this is just to save a little redundant
processing. The distance() method checks for the existance of the self.A
(or other such attribute) before calculating, and returns that if it
exists. It's all on a pretty small scale (note the default gridSize
value) so it probably doesn't matter much if I were to let it redo the
calculations every time. The distance calculation is not very intense,
probably: just your basic Pythagorean theorem:
{code}
diffX = abs(self.coord[0] - other.coord[0]) # difference in X coord.
diffY = abs(self.coord[1] - other.coord[1]) # difference in Y coord.
distance = ((diffX ** 2) + (diffY ** 2)) ** 0.5
{/code}
One solution would be to put the "exec" code in a function rather than
in the class method, but the class distance() method would still have to
rely on eval() -- and thus on the external data structure! -- to
retrieve the value. Am I right?
Maybe rather than storing all the distances as separate attributes, I
should maintain them all in a single self.distances list:
[(B, 5.0), (C, 1.414), (D, 7.6645), ...]
Then the distance(self, other) method filters self.distances for
"x[0] == str(other)". If found, return x[1], otherwise calculate the
distance and store it...
self.distances.append((other.name, distance))
other.distances.append((self.name, distance))
Simple, no "exec" statement to write nor eval() function to read the
values, and everything's done cleanly within the class methods.
Have I figured out my own solution?!? :) ("Operator, you can forget
about this call ... There's no one there I really wanted to talk
to!" :)[1] Anyway, comments would be appreciated, whether they're other
ideas or confirmation that I'm on the right track.
Really, I figured that out while I was writing this message. It sure
does some good to get away from IDLE every now and then. :)
Rob - /dev/rob0
[1] from an old Jim Croce song, "Operator", appx. 1971 (?)