Continuous types are quite rare in Python and third-party extensions; The OP rightly states: โfor linear algebra, use is enough that I don't seem to need to roll back my own,โ but all existing types that I know have mutable linear algebra! Thus, since the OP is adamant about immutability, there is nothing for it but a roll route.
Not that everything that was connected with a large number of operations, for example, if you need 2nd vectors:
import math class ImmutableVector(object): __slots__ = ('_d',) def __init__(self, x, y): object.__setattr__(self, _d, (x, y)) def __setattr__(self, n, v): raise ValueError("Can't alter instance of %s" % type(self)) @property def x(self): return self._d[0] @property def y(self): return self._d[1] def __eq__(self, other): return self._d == other._d def __ne__(self, other): return self._d != other._d def __hash__(self): return hash(self._d) def __add__(self, other): return type(self)(self.x+other.x, self.y+other.y) def __mul__(self, scalar): return type(self)(self.x*scalar, self.y*scalar) def __repr__(self): return '%s(%s, %s)' % (type(self).__name__, self.x, self.y) def __abs__(self): return math.hypot(self.x, self.y)
I โthrew for freeโ several additional functions, such as the .x and .y R / O properties, a nice string representation, ease of use in sets or as keys in dicts (why else need immutability?), Low memory, abs(v) to give the length of the vector v . I am sure that you can think of other โnot-it-cool-ifโ methods and operations, depending on your application field, and they will be just as easy. If you need other sizes, it will not be much more difficult, although less readable, since the .x , .y no longer applied ;-) (but I would use genexps, not map ).