Override .T (transpose) in subclass of numpy ndarray

允我心安 提交于 2020-08-26 07:57:06

问题


I have a three dimensional dataset where the 1st dimension gives the type of the variable and the 2nd and 3rd dimensions are spatial indexes. I am attempting to make this data more user friendly by creating a subclass of ndarray containing the data, but with attributes that have sensible names that point to the appropriate variable dimension. One of the variable types is temperature, which I would like to represent with the attribute .T. I attempt to set it like this:

self.T = self[8,:,:]

However, this clashes with the underlying numpy attribute for transposing an array. Normally, overriding a class attribute is trivial, however in this case I get an exception when I try to re-write the attribute. The following is a minimal example of the same problem:

import numpy as np

class foo(np.ndarray):
    def __new__(cls, input_array):
        obj = np.asarray(input_array).view(cls)
        obj.T = 100.0
        return obj

foo([1,2,3,4])

results in:

Traceback (most recent call last):
  File "tmp.py", line 9, in <module>
    foo([1,2,3,4])
  File "tmp.py", line 6, in __new__
    obj.T = 100.0
AttributeError: attribute 'T' of 'numpy.ndarray' objects is not writable

I have tried using setattr(obj, 'T', 100.0) to set the attribute, but the result is the same.

Obviously, I could just give up and name my attribute .temperature, or something else. However .T will be much more eloquent for the subsequent mathematical expressions which will be done with these data objects. How can I force python/numpy to override this attribute?


回答1:


For np.matrix subclass, as defined in np.matrixlib.defmatrix:

@property
def T(self):
    """
    Returns the transpose of the matrix.
    ....
    """
    return self.transpose()



回答2:


T is not a conventional attribute that lives in a __dict__ or __slots__. In fact, you can see this immediately because the result of T changes if you modify the shape or contents of an array.

Since ndarray is a class written in C, it has special descriptors for the dynamic attributes it exposes. T is one of these dynamic attributes, defined as a PyGetSetDef structure. You can't override it by simple assignment, because there is nothing to assign to, but you can make a descriptor that overrides it at the class level.

As @hpaulj's answer suggests, the simplest solution may be to use a property to implement the descriptor protocol for you:

import numpy as np

class foo(np.ndarray):
    @property
    def T(self):
        return self[8, :, :]

More complicated alternatives would be to make your own descriptor type, or even to extend the class in C and write your own PyGetSetDef structure. It all depends on what you are trying to achieve.




回答3:


Following Mad Physicist and hpaulj's lead, the solution to my minimal working example is:

import numpy as np

class foo(np.ndarray):
    def __new__(cls, input_array):
        obj = np.asarray(input_array).view(cls)
        return obj

    @property
    def T(self):
        return 100.0

x = foo([1,2,3,4])
print("T is", x.T)

Which results in:

T is [1 2 3 4]


来源:https://stackoverflow.com/questions/60877399/override-t-transpose-in-subclass-of-numpy-ndarray

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!