【发布时间】:2019-07-25 12:56:46
【问题描述】:
假设我想为 numpy 数组创建一个包装类 Image。我的目标是让它表现得像一个 2D 数组,但有一些额外的功能(这在这里并不重要)。我这样做是因为继承 numpy 数组比较麻烦。
import numpy as np
class Image(object):
def __init__(self, data: np.ndarray):
self._data = np.array(data)
def __getitem__(self, item):
return self._data.__getitem__(item)
def __setitem__(self, key, value):
self._data.__setitem__(key, value)
def __getattr__(self, item):
# delegates array's attributes and methods, except dunders.
try:
return getattr(self._data, item)
except AttributeError:
raise AttributeError()
# binary operations
def __add__(self, other):
return Image(self._data.__add__(other))
def __sub__(self, other):
return Image(self._data.__sub__(other))
# many more follow ... How to avoid this redundancy?
如您所见,我希望拥有所有用于数值运算的魔法方法,就像普通的 numpy 数组一样,但返回值为 Image 类型。所以这些魔术方法的实现,即__add__、__sub__、__truediv__等等,几乎是一样的,有点傻。我的问题是是否有办法避免这种冗余?
除了我在这里具体做的事情之外,有没有办法通过某种元编程技术在一个地方编写魔法方法,或者这是不可能的?我搜索了一些有关python元类的信息,但我仍然不清楚。
注意__getattr__ 不会处理魔术方法的委托。见this。
编辑
澄清一下,我理解继承是解决此类问题的一般解决方案,尽管我的经验非常有限。但我觉得继承 numpy 数组真的不是一个好主意。因为 numpy 数组需要处理视图转换和 ufunc(参见this)。当你在其他 py-libs 中使用你的子类时,你还需要考虑你的数组子类如何与其他数组子类相处。见我的stupid gh-issue。这就是我寻找替代品的原因。
【问题讨论】:
-
继承怎么比较麻烦?这听起来像是更好的方法。
-
因为 numpy 以比普通 python 类型更多的方式构造新的类似数组的对象(数组可以进行视图转换)。请参阅doc 了解更多信息。
-
你可能想看看
__array_function__协议(不过你需要一个最近的numpy) -
由于从
ndarray继承或编写像你这样的类的笨拙,更倾向于使用一些函数来进行专门的数组操作,并将类方法保留为更大您可以花时间完成全面工作的项目。np.matrix和np.ma是子类化ndarray的重要示例。 Python 为其集合提供了混合,但我不知道numpy的任何内容。
标签: python numpy metaprogramming