On Fri, Aug 20, 2010 at 12:55 PM, Gregory, Matthew
<matt.greg...@oregonstate.edu> 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]:
>> http://users.rcn.com/python/download/Descriptor.htm
>
> 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

perhaps properties could be of some use?

from operator import itemgetter, setitem

def named_index(index):
    getter = itemgetter(index)
    setter = lambda self, val: setitem(self, index, val)
    return property(getter, setter)

class NPoint(list):
    x = named_index(0)
    y = named_index(1)
    z = named_index(2)

p = NPoint([3, 4, 50])
print p.x, p.y, p.z
p.x = p.y + 13
print p

Note that trying to access z when there are not enough items in the
list will raise an IndexError, not an AttributeError. You might want
to adjust the getter/setter functions a little.

Alternatively, I'm not sure if you can add properties in __init__ or
__new__, but if not that, you can probably write a metaclass that adds
in the right properties based on list length.

Hugo
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to