Steven D'Aprano wrote: > It would surprise me greatly if numpy didn't already have such a class.
Yes, that is the first place I went looking, but I couldn't find such a class. I found one project using numpy for geometry objects (geometry-simple, http://code.google.com/p/geometry-simple/), but it doesn't look to be fully fleshed out. > Other than using numpy, probably the simplest solution is to just > subclass tuple and give it named properties and whatever other methods > you want. Here's a simple version: > > class Point(tuple): > def __new__(cls, *args): > if len(args) == 1 and isinstance(args, tuple): > args = args[0] > for a in args: > try: > a+0 > except TypeError: > raise TypeError('ordinate %s is not a number' % a) > return super(Point, cls).__new__(cls, args) > @property > def x(self): > return self[0] > @property > def y(self): > return self[1] > @property > def z(self): > return self[2] > def dist(self, other): > if isinstance(other, Point): > if len(self) == len(other): > sq_diffs = sum((a-b)**2 for (a,b) in zip(self, other)) > return math.sqrt(sq_diffs) > else: > raise ValueError('incompatible dimensions') > raise TypeError('not a Point') > def __repr__(self): > return "%s(%r)" % (self.__class__.__name__, tuple(self)) > > > class Point2D(Point): > def __init__(self, *args): > if len(self) != 2: > raise ValueError('need exactly two ordinates') > > class Point3D(Point): > def __init__(self, *args): > if len(self) != 3: > raise ValueError('need exactly three ordinates') > > These classes gives you: > > * immutability; > * the first three ordinates are named x, y and z; > * any ordinate can be accessed by index with pt[3]; > * distance is only defined if the dimensions are the same; > * nice string form; > * input validation. Thanks for this help. I'm curious as to why immutability would be an advantage here (or maybe that's not what you're suggesting). 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? 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. > What it doesn't give you (yet!) is: > > * distance between Points with different dimensions could easily be > defined just by removing the len() comparison. zip() will > automatically terminate at the shortest input, thus projecting the > higher-dimension point down to the lower-dimension point; > * other distance methods, such as Manhattan distance; > * a nice exception when you as for (say) pt.z from a 2-D point, instead > of raising IndexError; > * point arithmetic (say, adding two points to get a third). All good ideas, especially the different distance metrics to be defined in Point. I'm working on implementing these. > 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? thanks, matt _______________________________________________ Tutor maillist - [email protected] To unsubscribe or change subscription options: http://mail.python.org/mailman/listinfo/tutor
