【问题标题】:How to call `__rsub__` properly with a numpy array?如何使用 numpy 数组正确调用`__rsub__`?
【发布时间】:2019-10-16 08:32:01
【问题描述】:

考虑以下 sn-p:

import numpy as np

class MyClass:
    def __rsub__(self, other):
        print(type(other), other)

obj = MyClass()
arr = np.ones(3)

arr - obj

我希望它打印<class 'numpy.ndarray'> [1. 1. 1.]。 但实际上,它似乎对每个元素都调用了__rsub__

<class 'float'> 1.0
<class 'float'> 1.0
<class 'float'> 1.0

有什么方法可以告诉 numpy 我想要 first 行为,即将整个减法委托给MyClass

【问题讨论】:

    标签: python numpy numpy-ndarray


    【解决方案1】:

    在 NumPy 1.13+ 上,您可以使用 NumPy 特定的钩子来执行此操作,但一般情况下您不能让 __rsub__ 击败 __sub__ 方法。


    __rsub__ 如果左操作数的__sub__ 无法处理该操作,但左操作数可以 处理该操作,则尝试。 NumPy 数组的 __sub__ 将接受任何 RHS 并执行广播减法。您对象的 __rsub__ 仅对广播减法中的各个操作起作用。

    有一个非常有限的情况,首先尝试__rsub__,即如果 RHS 的类是 LHS 的类的子类。从技术上讲,您可以将numpy.ndarray 子类化,但这会带来很多 额外负担,并且对于numpy.matrix([[1]]) - obj 或其他子类仍然没有任何作用。

    没有办法说“我希望我的__rsub__ 赢得一切”。它不存在,存在也没有意义,因为如果你试图减去两个都想声明其方法的对象会胜过一切?


    所以这是一般情况。不过,特别是对于 NumPy,您可以挂钩到 numpy.ndarray.__sub__ 委托给的机制。

    NumPy 数组将 __sub__ 委托给 NumPy ufunc 机器。那里有一堆奇怪的自定义选项,但我们对一个特定选项的特定用途感兴趣:通过在类级别将 __array_ufunc__ 设置为 None,您可以声明一个与 ufunc 不兼容的类。这意味着所有 NumPy 运算符重载都将返回 NotImplemented,让您的类处理操作。这会影响 所有 运算符和更多的东西,但以您可能想要的方式:

    class MyClass:
        __array_ufunc__ = None
        def __rsub__(self, other):
            print(type(other), other)
    

    如果你想要比阻止所有 ufunc 更有针对性的东西,你可以实现一个实际的 __array_ufunc__ 方法,只处理 ufunc 是减法并且你的类的实例是 RHS 的情况:

    class MyClass:
        def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
            if ufunc is not numpy.subtract:
                return NotImplemented
            if method != '__call__':
                return NotImplemented
            if len(inputs) != 2 or inputs[1] is not self:
                return NotImplemented
            if kwargs:
                return NotImplemented
            return self.__rsub__(inputs[0])
        def __rsub__(self, other):
            print(type(other), other)
    

    【讨论】:

    • 感谢您的解释。有道理。
    • @lum:查看扩展答案以了解特定于 NumPy 的解决方法。一般来说,你不能让 __rsub__ 击败 __sub__ 方法,但你可以告诉 NumPy ufunc 机器不要处理你的类的实例。
    • 啊,真有趣!非常感谢您的指点,我相信这正是我想要的。
    • __array_priority__ 怎么样? stackoverflow.com/q/40252765/901925v
    • @hpaulj:这是开发人员想要删除的旧系统的一部分,所以我不想建议它。此外,知道什么是足够高的价值也存在问题。
    猜你喜欢
    • 1970-01-01
    • 2017-08-15
    • 2020-07-09
    • 2020-06-06
    • 1970-01-01
    • 2016-09-03
    • 1970-01-01
    • 2016-11-06
    • 1970-01-01
    相关资源
    最近更新 更多