【问题标题】:Override .T (transpose) in subclass of numpy ndarray在numpy ndarray的子​​类中覆盖.T(转置)
【发布时间】:2020-03-26 22:50:59
【问题描述】:

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

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

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

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 对于随后将使用这些数据对象完成的数学表达式将更有说服力。如何强制 python/numpy 覆盖此属性?

【问题讨论】:

  • 我想这是在 c 中实现的,所以你不能有充分的理由覆盖它。我认为 numpy 设置这个限制是可以接受的,因为它可能会破坏任意数量的利用 T 属性的函数,然后你就会有一个损坏的 numpy 数组。是什么阻止您使用T_?或temp?
  • T 不是实际属性。它是一个描述符,类似于检索新对象的属性。
  • 试试@property def T(self): return self[8,:,:]
  • 您不能将新属性写入数组,因为它没有__dict__。在 Python 中,您可以使用 __slots__ 进行模拟

标签: python numpy subclassing


【解决方案1】:

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

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

【讨论】:

  • 是的,就是这样做的。还要感谢@MadPhysicist 作为评论回答。
【解决方案2】:

T 不是存在于__dict____slots__ 中的常规属性。实际上,您可以立即看到这一点,因为如果您修改数组的形状或内容,T 的结果会发生变化。

由于ndarray 是一个用C 编写的类,它具有特殊的descriptors 用于它公开的动态属性。 T 是这些动态属性之一,定义为PyGetSetDef 结构。你不能通过简单的赋值来覆盖它,因为没有什么可以赋值的,但是你可以创建一个在类级别覆盖它的描述符。

正如@hpaulj's answer 建议的那样,最简单的解决方案可能是使用property 为您实现描述符协议:

import numpy as np

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

更复杂的选择是创建自己的描述符类型,或者甚至在 C 中扩展类并编写自己的 PyGetSetDef 结构。这完全取决于您要达到的目标。

【讨论】:

    【解决方案3】:

    按照 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]
    

    【讨论】:

    • 你有缩进问题
    • 您的财产不在班级内
    • 您的输出与您发布的代码不相关
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-04
    • 2016-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多