在 numpy ndarray 的子类中覆盖 .T(转置)

Override .T (transpose) in subclass of numpy ndarray

我有一个三维数据集,其中第一个维度给出了变量的类型,第二个和第三个维度是空间索引。我试图通过创建包含数据的 ndarray 的子 class 来使此数据更加用户友好,但具有指向适当变量维度的合理名称的属性。其中一种变量类型是温度,我想用属性 .T 来表示它。我尝试这样设置:

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

但是,这与用于转置数组的底层 numpy 属性冲突。通常,覆盖 class 属性是微不足道的,但是在这种情况下,当我尝试重写属性时出现异常。以下是同一问题的最小示例:

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])

结果:

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

我试过使用setattr(obj, 'T', 100.0)设置属性,但结果是一样的。

显然,我可以放弃并命名我的属性 .temperature,或其他名称。然而,.T 将更多 eloquent 对于将使用这些数据对象完成的后续数学表达式。如何强制 python/numpy 覆盖此属性?

对于 np.matrix 子类,定义在 np.matrixlib.defmatrix:

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

在 Mad Physicist 和 hpaulj 的带领下,我的最小工作示例的解决方案是:

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)

这导致:

T is [1 2 3 4]

T is not a conventional attribute that lives in a __dict__ or __slots__。事实上,您可以立即看到这一点,因为如果您修改数组的形状或内容,T 的结果会发生变化。

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 结构。您不能通过简单的赋值来覆盖它,因为没有任何东西可以分配给它,但是您可以创建一个描述符在 class 级别覆盖它。

作为 suggests, the simplest solution may be to use a property为您实现描述符协议:

import numpy as np

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

更复杂的替代方法是创建您自己的描述符类型,或者甚至在 C 中扩展 class 并编写您自己的 PyGetSetDef 结构。这完全取决于您要实现的目标。