Hi folks, I’ve got a subclass of numpy array that keeps track of the labels of the axes. E.g.
arr = AxesArray(np.arange(4).reshape(2,2), {"ax_time": 0, "ax_coord": 1})
arr.ax_time == 0 # true
arr.n_time == 2
However, when slicing changes the dimension of the array, I need to reassign the axes. So I implemented descriptors for ax_time
and ax_coord
(and ax_spatial
/ax_sample
), and now:
arr[1,:].ax_coord == 0 # true
arr.n_time == 1
However, some people want to use ax_feature
instead of ax_coord
, which means that the axis attributes have to be determined at instantiation. I’m having trouble assigning these dynamically, e.g.:
class AxisName:
def __set_name__(self, owner, name):
self.public_name = name
self.private_name = '_' + name
def __get__(self, obj, objtype=None):
return getattr(obj, self.private_name)
def __set__(self, obj, value):
setattr(obj, self.private_name, value)
class Foo:
def __init__(self, axes):
for ax_name, axis in axes.items():
desc = AxisName()
desc.__set_name__(self, ax_name)
desc.__set__(self, axis)
setattr(self, ax_name, desc)
temp = Foo({"ax_time": 0, "ax_spatial": [1, 2]})
temp.ax_time
# <__main__.AxisName at 0x7f4a25ff5ff0>
This took a second to figure out, but makes sense: the Descriptor tutorial says that __getattribute__
checks class variables to determine if the attribute is a descriptor. I tried adding these names to the class:
Foo.ax_time = AxisName()
temp.ax_time
# AttributeError: AxisName object has no attribute 'private_name"
Ok so I must need to rerun __set_name__
. But rewinding a bit and setting the name yields the same result:
desc = temp.ax_time
Foo.ax_time = AxisName()
desc.__set_name__(temp, "ax_time")
temp.ax_time
# AttributeError: 'AxisName' object has no attribute 'private_name
So I know there’s an option to have a single descriptor, axes
, and to handle temp.ax_whateverr
via __getattr__
. But is there a way to properly assign descriptors dynamically? Am I misunderstanding something about owner
, __set_name__
, and how descriptors are created?