[Tutor] design of Point class

Steven knotty at pearwood.info
Tue Aug 24 01:14:34 CEST 2010


On Tue, 24 Aug 2010 04:36:31 am Gregory, Matthew wrote:

> I'm curious as to why immutability would be an
> advantage here (or maybe that's not what you're suggesting). 

Immutability is *always* an advantage for numeric types.

You can use immutable objects as keys in dicts.

You can (if you want) optimise the class so that it caches instances, 
thus saving memory.

You can be sure that invariants remain true. If an immutable instance 
has to be, say, positive, once you've checked that it is positive once 
you can be sure than no function can change it to be negative.

Look at the standard Python numeric types:

int, long, float, decimal.Decimal, fractions.Fraction 

They are all immutable. That should tell you something :)


> Typically, I would want to be able to do 'p.x = 10', so subclassing
> from a list (or numpy nd-array perhaps) would make more sense in my
> case?

Why do you want to modify points rather than create new ones as needed?

In any case, you should not subclass from list. It makes no sense to 
have pt.sort() or pt.pop() or various other list-like methods. 
Subclassing list is not the way. If you insist on mutable points, then 
something like:

class MutablePoint(object):
    def __init__(self, *ordinates):
        self._ordinates = list(ordinates)
    def __getitem__(self, i):
        return self._ordinates[i]
    def __setitem__(self, i, x):
        self._ordinates[i] = x
    

and so forth.



> Further, if I use setters, can I still use decorators as you've 
> outlined or do I need to do use 'x = property(get, set)'.  These are
> all new language constructs that I haven't encountered yet.

In Python 2.5, the only way to pass a setter and/or deleter to property 
is by using the form x = property(getter, setter, deleter). In Python 
2.6, properties gain methods that let you do this:

@property
def x(self): return self._x
@x.setter
def x(self, value): self._x = value
@x.deleter
def x(self): del self._x

Note that you MUST use the same name (x in the above example) for the 
getter, setter and deleter.

[...]
> > An alternative would be to have the named ordinates return 0 rather
> > than raise an error. Something like this would work:
> >
> >     @property
> >     def y(self):
> >         try: return self[1]
> >         except IndexError: return 0
>
> Is there an advantage to doing this?  Wouldn't this make one falsely
> assume that y was defined and equal to 0?

That's why it's an alternative.

If you decide that for your application it makes sense to treat 
coordinates on the XY plane as equivalent to coordinates in the XYZ 
space with Z=0, that's the simplest way to implement it.



-- 
Steven


More information about the Tutor mailing list