I am attempting to subclass a numpy structured array so that I can add special methods to the subclass. Everything works fine until I retrieve a single index from the array. When this occurs, an object of type numpy.void is returned instead of the subclass's type. (Actually, whether subclassing or not, retrieving a single index from a structured array returns an object of type numpy.void.) Why is this? And how can I ensure that an instance of my class is returned? I assume that overriding __getitem__ would be the way to go, but I'm not familiar enough with ndarray subclassing to be confident that I would not screw up something else. Please advise.
Here is an example of the behavior I am describing:
import numpy as np
# The ndarray subclass
class Foo(np.ndarray):
# Do something special that uses a field of the structured array
def bar(self):
return self['BAR']
def main():
# Set up the structured array
arr = np.arange((3+2)*2,dtype=np.float64).view(dtype=np.dtype([('BAR',np.float64,3),('other',np.float64,2)]))
# Get a Foo instance using the data
obj = arr.view(Foo)
print 'type(obj): ',type(obj) # As expected: Foo object
print 'type(obj[:1]): ',type(obj[:1]) # As expected: Foo object
print 'type(obj[0]): ',type(obj[0]) # Why numpy.void???
print 'obj.bar():' # As expected
print obj.bar() # As expected
print 'obj[:1].bar():',obj[:1].bar() # As expected
print 'obj[0].bar(): ',obj[0].bar() # Causes exception: AttributeError: 'numpy.void' object has no attribute 'bar'
if __name__=="__main__":
main()
The output is as follows:
type(obj): <class '__main__.Foo'>
type(obj[:1]): <class '__main__.Foo'>
type(obj[0]): <type 'numpy.void'>
obj.bar():
[[ 0. 1. 2.]
[ 5. 6. 7.]]
obj[:1].bar(): [[ 0. 1. 2.]]
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/site-packages/ipdb/__main__.py", line 138, in main
pdb._runscript(mainpyfile)
File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/pdb.py", line 1233, in _runscript
self.run(statement)
File "/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/bdb.py", line 387, in run
exec cmd in globals, locals
File "", line 1, in
File "scratch.py", line 1, in
import numpy as np
File "scratch.py", line 25, in main
print 'obj[0].bar(): ',obj[0].bar() # Causes exception: AttributeError: 'numpy.void' object has no attribute 'bar'
AttributeError: 'numpy.void' object has no attribute 'bar'
obj[0].bar(): Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program