如何通过像__rsub__
这样的右手操作符传递numpy数组的属性?
我在python中编写了一个非常简单的类,它定义了两个函数:
class test(object):
def __sub__(self, other):
return other
def __rsub__(self, other):
return other
基本上他们也应该这样做。左侧运算符__sub__
按预期工作,但似乎numpy数组在右侧运算符上的属性上被删除
from skimage import data
from skimage.color import rgb2gray
lena = data.lena()
grayLena = rgb2gray(lena)
t = test()
## overloaded - operator
left_hand = t - grayLena
print left_hand
# Output:
#array([[ 0.60802863, 0.60802863, 0.60779059, ..., 0.64137412,
# 0.57998235, 0.46985725],
# [ 0.60802863, 0.60802863, 0.60779059, ..., 0.64137412,
# 0.57998235, 0.46985725],
# [ 0.60802863, 0.60802863, 0.60779059, ..., 0.64137412,
# 0.57998235, 0.46985725],
# ...,
# [ 0.13746353, 0.13746353, 0.16881412, ..., 0.37271804,
# 0.35559529, 0.34377725],
# [ 0.14617059, 0.14617059, 0.18730588, ..., 0.36788784,
# 0.37292549, 0.38467529],
# [ 0.14617059, 0.14617059, 0.18730588, ..., 0.36788784,
# 0.37292549, 0.38467529]])
right_hand = grayLena - t
print right_hand
# Output:
# array([[0.6080286274509803, 0.6080286274509803, 0.6077905882352941, ...,
# 0.6413741176470589, 0.5799823529411765, 0.4698572549019608],
# [0.6080286274509803, 0.6080286274509803, 0.6077905882352941, ...,
# 0.6413741176470589, 0.5799823529411765, 0.4698572549019608],
# [0.6080286274509803, 0.6080286274509803, 0.6077905882352941, ...,
# 0.6413741176470589, 0.5799823529411765, 0.4698572549019608],
# ...,
# [0.1374635294117647, 0.1374635294117647, 0.1688141176470588, ...,
# 0.3727180392156863, 0.35559529411764706, 0.34377725490196076],
# [0.1461705882352941, 0.1461705882352941, 0.18730588235294118, ...,
# 0.3678878431372549, 0.37292549019607846, 0.3846752941176471],
# [0.1461705882352941, 0.1461705882352941, 0.18730588235294118, ...,
# 0.3678878431372549, 0.37292549019607846, 0.3846752941176471]], dtype=object)
因此,两个操作之间的区别在于__rsub__
接收到dtype = object的数组。如果我只是设置这个数组的dtype,一切都会正常工作。
但是,它仅适用于__rsub__
之外的返回值。在我的__rsub__
里面我只得到了垃圾,我无法转换回来,即如果我做了
npArray = np.array(other, dtype=type(other))
我得到一个类型的一维数组(在我的情况下浮动)。但由于某种原因,形状信息丢失了。有没有人这样做或者想法如何访问数组的原始属性(形状和类型)?
答案 0 :(得分:1)
我不确定ndarray
机器内部的确切控制流程是什么,但在你的情况下发生的事情或多或少是明确的:
委托给对象的ndarray
方法的__rsub__
不是整个减法操作,而是来自数组中每个项目的对象的减法。显然,当必须将操作委托给对象的方法时,无论返回什么内容,返回类型都设置为object
。您可以通过稍微修改代码来检查它:
class test(object):
def __sub__(self, other):
return other
def __rsub__(self, other):
return other if other != 1 else 666
In [11]: t = test()
In [12]: t - np.arange(4)
Out[12]: array([0, 1, 2, 3])
In [13]: np.arange(4) - t
Out[13]: array([0, 666, 2, 3], dtype=object)
我认为没有一种简单的方法来覆盖这种行为。您可以尝试making test
a subclass of ndarray
__array_priority__
高__array_wrap__
并稍微滥用class test(np.ndarray):
__array_priority__ = 100
def __new__(cls):
obj = np.int32([1]).view(cls)
return obj
def __array_wrap__(self, arr, context) :
if context is not None :
ufunc = context[0]
args = context[1]
if ufunc == np.subtract :
if self is args[0] :
return args[1]
elif self is args[1] :
return args[0]
return arr
方法:
>>> t = test()
>>> np.arange(4) - t
array([0, 1, 2, 3])
>>> t - np.arange(4)
array([0, 1, 2, 3])
现在:
>>> np.arange(4) + t
test([1, 2, 3, 4])
>>> t + np.arange(4)
test([1, 2, 3, 4])
可是:
1
这有点浪费,因为我们正在对t
内部{{1}}添加到数组中的每个值,然后默默地丢弃它,但我无法想到任何超越的方式。