简体   繁体   English

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

[英]Override .T (transpose) in subclass of numpy ndarray

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.我试图通过创建一个包含数据的ndarray子类来使这些数据更加用户友好,但具有指向适当变量维度的合理名称的属性。 One of the variable types is temperature, which I would like to represent with the attribute .T .变量类型之一是温度,我想用属性.T表示它。 I attempt to set it like this:我尝试这样设置:

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

However, this clashes with the underlying numpy attribute for transposing an array.但是,这与用于转置数组的底层 numpy 属性发生冲突。 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.我曾尝试使用setattr(obj, 'T', 100.0)来设置属性,但结果是一样的。

Obviously, I could just give up and name my attribute .temperature , or something else.显然,我可以放弃并将我的属性.temperature或其他名称。 However .T will be much more eloquent for the subsequent mathematical expressions which will be done with these data objects.然而, .T对于随后将使用这些数据对象完成的数学表达式来说会更有说服力。 How can I force python/numpy to override this attribute?如何强制 python/numpy 覆盖此属性?

For np.matrix subclass, as defined in np.matrixlib.defmatrix:对于np.matrix子类,如 np.matrixlib.defmatrix 中所定义:

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

Following Mad Physicist and hpaulj's lead, the solution to my minimal working example is:遵循 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)

Which results in:结果是:

T is [1 2 3 4]

T is not a conventional attribute that lives in a__dict__ or __slots__ . T不是存在于__dict____slots__的常规属性。 In fact, you can see this immediately because the result of T changes if you modify the shape or contents of an array.事实上,您可以立即看到这一点,因为如果您修改数组的形状或内容, T的结果会发生变化。

Since ndarray is a class written in C, it has special descriptors for the dynamic attributes it exposes.由于ndarray是用 C 编写的类,因此它具有用于公开的动态属性的特殊描述符 T is one of these dynamic attributes, defined as a PyGetSetDef structure. T是这些动态属性之一,定义为PyGetSetDef结构。 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 aproperty to implement the descriptor protocol for you:正如@hpaulj 的回答所暗示的那样,最简单的解决方案可能是使用property为您实现描述符协议:

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.更复杂的替代方法是创建自己的描述符类型,甚至扩展 C 中的类并编写自己的PyGetSetDef结构。 It all depends on what you are trying to achieve.这一切都取决于您要实现的目标。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM