gpt4 book ai didi

python - 如何使 __add__ 的 numpy 重载独立于操作数顺序?

转载 作者:太空狗 更新时间:2023-10-30 00:55:58 35 4
gpt4 key购买 nike

在包含 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__ 导致分段故障...我想我做错了什么。

有什么建议适用于上面的简单示例(同时保留 __array__ 属性)?

编辑:我不希望 A 成为 np.ndarray 的子类,因为这会带来我想避免的其他并发症 - 至少现在是这样。请注意,pandas 似乎已经解决了这个问题:

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 解决方案之外,还可以将 __array_wrap__ 属性添加到类 A(以避免子类化)。更多 here .根据 seberg 的说法,__array_priority__ 也可以在较新的 numpy 版本上工作(见评论)。

最佳答案

使A 成为np.ndarray 的子类,Python 将首先 调用您的A.__radd__ 方法。

来自object.__radd__ documentation :

Note: If the right operand’s type is a subclass of the left operand’s type and that subclass provides the reflected method for the operation, this method will be called before the left operand’s non-reflected method. This behavior allows subclasses to override their ancestors’ operations.

通过子类化您的 A 对象确实能够拦截添加:

>>> import numpy as np
>>> class A(np.ndarray):
... """ 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(np.arange(5))
>>> a + np.ones(5)
A object: array([ 1., 2., 3., 4., 5.])
>>> np.ones(5) + a
A object: array([ 1., 2., 3., 4., 5.])

研究 Subclassing ndarray documenation注意事项和影响。

关于python - 如何使 __add__ 的 numpy 重载独立于操作数顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22632937/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com