【发布时间】:2014-03-25 11:16:50
【问题描述】:
在包含 numpy 数组作为属性的类中重载运算符时遇到问题。根据操作数的顺序,结果类型将是我的 A 类(期望的行为)或 numpy 数组。如何让它总是返回一个 A 的实例?
例子:
import numpy as np
class A(object):
""" class overloading a numpy array for addition
"""
def __init__(self, values):
self.values = values
def __add__(self, x):
""" addition
"""
x = np.array(x) # make sure input is numpy compatible
return A(self.values + x)
def __radd__(self, x):
""" reversed-order (LHS <-> RHS) addition
"""
x = np.array(x) # make sure input is numpy compatible
return A(x + self.values)
def __array__(self):
""" so that numpy's array() returns values
"""
return self.values
def __repr__(self):
return "A object: "+repr(self.values)
A 的一个实例:
>>> a = A(np.arange(5))
这按预期工作:
>>> a + np.ones(5)
A object: array([ 1., 2., 3., 4., 5.])
这不是:
>>> np.ones(5) + a
array([ 1., 2., 3., 4., 5.])
尽管这样很好:
>>> list(np.ones(5)) + a
A object: array([ 1., 2., 3., 4., 5.])
在第二个示例中发生的情况是根本没有调用 radd,而是调用了 np.ones(5) 中的 numpy 方法 __add__。
我尝试了来自 this post 的一些建议,但 __array_priority__ 似乎没有任何区别(在 seberg 评论后编辑:至少在 numpy 1.7.1 中,但可以在较新的版本上工作),并且 __set_numeric_ops__ 领导到 Segmentation Fault... 我想我做错了什么。
对上述简单示例有任何建议(同时保留__array__ 属性)?
编辑:我不希望 A 成为 np.ndarray 的子类,因为这会带来我想避免的其他并发症——至少现在是这样。请注意,熊猫似乎已经解决了这个问题:
import pandas as pd
df = pd.DataFrame(np.arange(5))
type(df.values + df) is pd.DataFrame # returns True
isinstance(df, np.ndarray) # returns False
我很想知道这是怎么做到的。
解决方案:除了子类化的M4rtini解决方案外,还可以在A类中添加__array_wrap__属性(避免子类化)。更多here。根据 seberg 的说法,__array_priority__ 也可以在较新的 numpy 版本上工作(见评论)。
【问题讨论】:
-
如果添加
__array__,则添加__array_priority__,不确定是否涵盖旧版本的所有内容。 -
有什么特殊的方法可以做到这一点吗?如果我只是添加一个类属性
__array_priority__ = 1000,并不能解决问题。我也尝试了 0, -1 ...我的 numpy 版本是 1.7.1,这是相当新的,不是吗? -
你没走多远,
__array_wrap__成功了(见下面的答案) -
相当新,但还不够我的意思。
标签: python arrays numpy operator-overloading