如何使 math 和 numpy 模块中的现有函数支持用户定义的对象?

How do I make existing functions in math and numpy module support user-defined objects?

我定义了一个 class,我希望它支持 +- 等基本运算,甚至支持 sin 等更高级的数学运算。也就是说,我需要为这些基本运算符和数学函数定义一些新规则。

我可以使用 Python 的魔法方法来处理基本运算符,

class NewObj():

    def __init__(self, *args):
        pass

    def __add__(self, other):
        pass

    def __mul__(self, other):
        pass

    # Use magic methods to define other basic operators below...

而且我还可以在定义了 class NewObj 的同一个 .py 文件中重新定义基本函数,例如

def sin(x):
    pass

并将此文件命名为 myoperator.py。然后我可以导入此模块并对 NewObj 对象应用新操作。


但我还希望 numpymath 中的现有函数支持我的 NewObj 对象,以便 math.sin()numpy.sin() 也支持我新定义的NewObj 个对象。我怎样才能做到这一点?

另一个问题是:是否可以像魔术方法一样将函数封装在我的 NewObj class 中,以便所有的东西都写在 class 数据结构中?

您可以重新定义 math 模块的 sin

import math

class NewObj:
    pass

old_sin = math.sin

def new_sin(number):
    return 42.0 if isinstance(number, NewObj) else old_sin(number)

math.sin = new_sin

大概您用更有用的定义替换了 42.0

希望不久的将来会有一个 __numpy_ufunc__ 特殊属性(名称受 change). Here's the relevant bit from the numpy docs' dev version

class.__numpy_ufunc__(ufunc, method, i, inputs, **kwargs)

New in version 1.11.

Any class (ndarray subclass or not) can define this method to override behavior of NumPy’s ufuncs.

[强调我的]

math 模块明确记录了像 math.sin 这样的功能总是 return 浮动。如果你想 math.sin(your_object) 到 return 一个 NewObj 实例而不是 float不要那样做 。即使你让它工作,它也会让每个人都感到困惑,它会导致初始化顺序错误和其他令人头疼的问题。 (NumPy 有自己的 numpy.sin 而不是试图让 math.sin 支持 NumPy 数组是有原因的。)

如果您不介意 math.sin(your_object) return 使用浮点数,则实施 __float__ 方法将您的对象转换为浮点数:

class NewObj(object):
    ...
    def __float__(self):
        return whatever

math.sin 会将您的对象转换为浮点数,计算浮点数的正弦值,然后 return 将正弦值作为浮点数。


对于 NumPy,只需实现一个 sin 方法:

class NewObj(object):
    ...
    def sin(self):
        return whatever

numpy.sin 将委托给您的 sin 方法。你可以拥有它return一个NewObj;没有必要投射到浮动或任何东西。大多数类似的 NumPy 函数将类似地委托给方法。也就是说,尝试在 NumPy 数组中使用自定义对象会破坏 NumPy 的大部分效率优势,因此如果您想这样做,您可能需要重新考虑您的设计。