# [Tutor] design of Point class

bob gailer bgailer at gmail.com
Sat Aug 21 02:35:01 CEST 2010

```  On 8/20/2010 1:55 PM, Gregory, Matthew wrote:
> Wayne Werner wrote:
>> class Point2D(PointND):
>>      def __init__(self, x = 0, y = 0):
>>          super(Point2D, self).__init__([x,y])
>>          self.x = 0
>>          self.y = 0
>>
>> though you wouldn't be able to directly modify the values, or you'll
>> lose the distance function. You'd have to create setter functions, and as
>> such should rename x and y to _x and _y, to indicate that sure you *can* touch
>> these, but really you shouldn't.
>>
>> For the 3d, you'd just add a z param, although to really generalize your
>> ND class you could do this instead:
>>
>> class PointND(object):
>>     def __init__(self, x=0, y=0, z=0, a_list=None):
>>         if a_list is not None:
>>             self.a_list = a_list[:]
>>         self.x = x
>>         self.y = y
>>         self.z = z
>>
>>     def coords(self):
>>         return [self.x, self.y, self.z] + self.a_list
>>     ...
>>
>> Then your subclass takes less effort:
>>
>> class Point2D(PointND):
>>      def __init__(self, x=0, y=0):
>>          super(Point2D, self).__init__(x,y)
>>
>> and this allows you to access point.x, point.y, and point.z directly.
>>
>> Of course you could also subclass list with ND and just use descriptors
>> for self[0], self[1], and self[2]:
> Thanks all for good suggestions.  I'm intrigued by the idea of subclassing list (suggested by both Bob and Wayne) and using x, y and z as descriptors to the elements in the list.  Obviously, it's important that the descriptors (x,y,z) stay in sync with the list itself so that:
>
>    >>>  p = PointND(1,2,3)
>    >>>  p.x = 10
>    >>>  p
>    [10,2,3]
>
> > From what I understood of the link Wayne sent, I should be able to use __set__ to create this relationship between the labels and the list, but I'm totally lost on how to do this.  It seems like x,y,z need to be instances of descriptor objects who have values that are associated with the list.
>
> In the mean time, I've overridden __setattr__ to enforce this, but it looks a bit crufty.  Any further suggestions are most welcome.
>
> class PointND(list):
>      def __init__(self, *a_list):
>          super(PointND, self).__init__(a_list)
>          if len(self)<= 3:
>              self.x = self[0]
>          if len(self)>= 2 and len(self)<= 3:
>              self.y = self[1]
>          if len(self) == 3:
>              self.z = self[2]
>
>      def __setattr__(self, attr, value):
>          if attr in ('x', 'y', 'z'):
>              self.__dict__[attr] = value
>              if attr == 'x':
>                  self[0] = value
>              elif attr == 'y':
>                  self[1] = value
>              else:
>                  self[2] = value

After more thought it gets even better:

class PointND(list):
def __init__(self, *a_list):
super(PointND, self).__init__(a_list)

def get(ix):
def g(self):
if len(self) >=  ix + 1:
return self[ix]
else:
raise AttributeError
return g

def set(ix):
def s(self, value):
if len(self) >=  ix + 1:
self[ix] = value
else:
raise AttributeError
return s

x = property(get(0), set(0))
y = property(get(1), set(1))
z = property(get(2), set(2))

--
Bob Gailer
919-636-4239
Chapel Hill NC

```