[Numpy-discussion] subclassing matrix
Basilisk96
basilisk96 at gmail.com
Thu Jan 10 01:08:03 EST 2008
Hello folks,
In the course of a project that involved heavy use of geometry and
linear algebra, I found it useful to create a Vector subclass of
numpy.matrix (represented as a column vector in my case).
I'd like to hear comments about my use of this "class promotion"
statement in __new__:
ret.__class__ = cls
It seems to me that it is hackish to just change an instance's class
on the fly, so perhaps someone could clue me in on a better practice.
Here is my reason for doing this:
Many applications of this code involve operations between instances of
numpy.matrix and instances of Vector, such as applying a linear-
operator matrix on a vector. If I omit that "class promotion"
statement, then the results of such operations cannot be instantiated
as Vector types:
>>> from vector import Vector
>>> import numpy
>>> u = Vector('1 2 3')
>>> A = numpy.matrix('2 0 0; 0 2 0; 0 0 2')
>>> p = Vector(A * u)
>>> p.__class__
<class 'numpy.core.defmatrix.matrix'>
This is undesirable because the calculation result loses the custom
Vector methods and attributes that I want to use. However, if I use
that "class promotion" statement, the p.__class__ lookup returns what
I want:
>>> p.__class__
<class 'vector.Vector'>
Is there a better way to achieve that?
Here is the partial subclass code:
#---------- vector.py
import numpy as _N
import math as _M
#default tolerance for equality tests
TOL_EQ = 1e-6
#default format for pretty-printing Vector instances
FMT_VECTOR_DEFAULT = "%+.5f"
class Vector(_N.matrix):
"""
2D/3D vector class that supports numpy matrix operations and more.
Examples:
u = Vector([1,2,3])
v = Vector('3 4 5')
w = Vector([1, 2])
"""
def __new__(cls, data="0. 0. 0.", dtype=_N.float64):
"""
Subclass instance constructor.
If data is not specified, a zero Vector is constructed.
The constructor always returns a Vector instance.
The instance gets a customizable Format attribute, which
controls the printing precision.
"""
ret = super(Vector, cls).__new__(cls, data, dtype=dtype)
#promote the instance to cls type.
ret.__class__ = cls
assert ret.size in (2, 3), 'Vector must have either two or
three components'
if ret.shape[0] == 1:
ret = ret.T
assert ret.shape == (ret.shape[0], 1), 'could not express
Vector as a Mx1 matrix'
if ret.shape[0] == 2:
ret = _N.vstack((ret, 0.))
ret.Format = FMT_VECTOR_DEFAULT
return ret
def __str__(self):
fmt = getattr(self, "Format", FMT_VECTOR_DEFAULT)
fmt = ', '.join([fmt]*3)
return ''.join(["(", fmt, ")"]) % (self.X, self.Y, self.Z)
def __repr__(self):
fmt = ', '.join(['%s']*3)
return ''.join(["%s([", fmt, "])"]) %
(self.__class__.__name__, self.X, self.Y, self.Z)
#### the remaining methods are Vector-specific math operations,
including the X,Y,Z properties...
Cheers,
-Basilisk96
More information about the NumPy-Discussion
mailing list