如何使 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
对象应用新操作。
但我还希望 numpy
和 math
中的现有函数支持我的 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 的大部分效率优势,因此如果您想这样做,您可能需要重新考虑您的设计。
我定义了一个 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
对象应用新操作。
但我还希望 numpy
和 math
中的现有函数支持我的 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 的大部分效率优势,因此如果您想这样做,您可能需要重新考虑您的设计。