I've created a subclass of ndarray called "Parray" which takes two arguments: p, and dimensionality. It works fine on its own. Now, I want to create a class called SirPlotsAlot, which inherits Parray without all the fancy new and array_finalize etc.
import numpy as np
class Parray(np.ndarray):
def __new__(self, p = Parameters(), dimensionality = 2):
print "Initializing Parray with initial dimensionality %s..." % dimensionality
self.p = p # store the parameters
if dimensionality == 2:
shape = (p.nx, p.ny)
self.pshape = shape
elif dimensionality == 3:
shape=(p.nx, p.ny, p.nx)
self.pshape = shape
else:
raise NotImplementedError, "dimensionality must be 2 or 3"
# ...Set other variables (ellided)
subarr = np.ndarray.__new__(self, shape, dtype, buffer, offset, strides, order)
subarr[::] = np.zeros(self.pshape) # initialize to zero
return subarr
...
class SirPlotsAlot(Parray):
def __init__(self, p = Parameters(), dimensions = 3):
super(SirPlotsAlot, self).__new__(p, dimensions) # (1)
Objects in my program share sets of parameters by passing an object p = Parameters() back and forth.
Now, when I type (the file is auxiliary.py):
import auxiliary
from parameters import Parameters
p = Parameters()
s = auxiliary.SirPlotsAlot(p, 3)
expecting to get a nice "Initializing Parray with initial dimensionality 3", I get "2", instead. BUT if I type:
import auxiliary
s = auxiliary.SirPlotsAlot()
I get
---> 67 shape = (p.nx, p.ny)
"AttributeError: 'int' object has no attribute 'nx'"
It thinks "p" is an int, which it is not. I can get lots of weird seemingly unrelated errors if I play around with it. The int it thinks it is is "2". I'm completely lost.
I've tried with and without the # (1) comment (the super call).
Other errors from playing around include "AttributeError: 'list' object has no attribute 'p'", "TypeError: new() takes exactly 2 arguments (1 given)", "ValueError: need more than 0 values to unpack" (I replaced new's arguments with *args, something I don't understand very well).
It's been ten years and I long left the project, but I resolved this issue by creating helper functions to create new classes and set them up. In the code example below, see the definitions at the bottom of the file. I imported and used those.
Props to Matthew Schinckel to pointing out that
__new__
should have already been called by the time__init__
runs, and to everyone else for their thoughts.