首页 > 解决方案 > 了解 `np.ndarray` 子类化中的默认值

问题描述

我正在阅读numpy有关 subclassing 的文档ndarray,但在设置默认值方面,我观察到的结果与描述的结果略有不同。该文档似乎说应该使用一个位置来设置额外属性的默认值,但我发现在两个位置保持正确的默认值是必要的。

考虑文档中描述的实际示例,在此处复制(为简洁起见,注释已重新格式化):

import numpy as np

class RealisticInfoArray(np.ndarray):

    def __new__(cls, input_array, info=None):
        obj = np.asarray(input_array).view(cls)
        obj.info = info
        return obj

    def __array_finalize__(self, obj):
        # Note that it is here, rather than in the __new__ method,
        # that we set the default value for 'info', because this
        # method sees all creation of default objects - with the
        # InfoArray.__new__ constructor, but also with
        # arr.view(InfoArray).
        if obj is None: return
        self.info = getattr(obj, 'info', None)

描述默认值生效位置的注释让我感到困惑。我替换了默认值以查看发生了什么,例如:info='michelangelo'in__new__getattr(obj, 'info', 'donatello')in __array_finalize__。我发现后者只设置了view创建方法,而前者用于显式构造函数调用和from-template创建:

>>> a = RealisticInfoArray(np.arange(10)); print(a.info)
michelangelo
>>> b = np.arange(10).view(RealisticInfoArray); print(b.info)
donatello
>>> c = a[1:]; print(c.info)
michelangelo

a在这种情况下,根据我对文档的阅读,它看起来像是采用了“错误”的默认值。据我所知,a.info在 中设置正确__array_finalize__,但随后被默认的 from 覆盖__new__

首先,我是不是搞错了?如果没有,我是否需要在两个地方都保持预期的默认值,或者有没有办法将其减少到一个?(我在下面的回答中对此进行了尝试,感谢任何反馈。)

标签: pythonnumpysubclass

解决方案


我目前的解决方法(除了维护两个默认值)是提供一个类属性 ,DEFAULT_INFO可以由__new__和访问__array_finalize__

import numpy as np

class RealisticInfoArray(np.ndarray):

    DEFAULT_INFO = 'michelangelo'

    def __new__(cls, input_array, info=None):
        obj = np.asarray(input_array).view(cls)
        if info is None:
            info = obj.DEFAULT_INFO
        obj.info = info
        return obj

    def __array_finalize__(self, obj):
        if obj is None: return
        self.info = getattr(obj, 'info', self.DEFAULT_INFO)

正确产生:

>>> a = RealisticInfoArray(np.arange(10)); print(a.info)
michelangelo
>>> b = np.arange(10).view(RealisticInfoArray); print(b.info)
michelangelo
>>> c = a[1:]; print(c.info)
michelangelo

这还有一个额外的好处,即类的用户可以修改默认值(例如RealisticInfoArray.DEFAULT_INFO = 'leonardo'),并在他们认为合适的时候使用他们自己的默认值。但是,我尚未测试此解决方案的意外副作用。


推荐阅读