我知道具有复数的比较运算符一般不能定义。这就是为什么python在尝试使用开箱即用的复杂比较时抛出TypeError
异常的原因。我理解为什么会出现这种情况(请不要试图解释为什么不能比较两个复杂的数字)。
那就是说,在这种特殊情况下,我想根据它们的大小来实现复数比较。换句话说,对于z1
和z2
复数值,z1 > z2
if-and-only-if abs(z1) > abs(z2)
,其中abs()
实现复数幅度,如在numpy.abs()
。
我想出了一个解决方案(至少我认为我有)如下:
import numpy as np
class CustomComplex(complex):
def __lt__(self, other):
return np.abs(self) < np.abs(other)
def __le__(self, other):
return np.abs(self) <= np.abs(other)
def __eq__(self, other):
return np.abs(self) == np.abs(other)
def __ne__(self, other):
return np.abs(self) != np.abs(other)
def __gt__(self, other):
return np.abs(self) > np.abs(other)
def __ge__(self, other):
return np.abs(self) >= np.abs(other)
complex = CustomComplex
这似乎有效,但我有几个问题:
complex
数据类型以及numpy.complex
。如何在没有代码重复的情况下优雅地完成这项工作?答案 0 :(得分:5)
我担心我会偏离主题(是的,我完全阅读了你的帖子:-))。好的,Python允许你尝试比较复杂的数字,因为你可以单独定义所有运算符,即使我强烈建议你不重新定义__eq__
,就像你做的那样:你是说1 == -1
!
恕我直言,问题就在那里,并且会在某一时刻(或在任何使用你的包裹的人面前)涌现:当使用平等和不平等时,普通凡人(以及大多数蟒蛇代码)会做出简单的假设,例如{ {1}},-1 != 1
隐含(a <= b) && (b <= a)
。由于纯粹的数学原因,你根本无法同时将这两个假设成立。
另一个经典假设是a == b
等同于a <= b
。但是,预订-b <= -a
相当于a <= b
!
话虽如此,我会尽力回答你的两个问题:
代码示例(基于您自己的代码,但未经过广泛测试):
-a <= -b
答案 1 :(得分:1)
根据您的要求,我会放弃为什么这可能是一个坏主意的所有原因。
这是要走的路还是有更好的选择?
当正常abs
接受复数并且速度快得多时,无需使用numpy。如果你想减少代码(但这可能会更慢),那么total_ordering
中的functools
也可以很方便地进行这种简单的比较:
from functools import total_ordering
@total_ordering
class CustomComplex(complex):
def __eq__(self, other):
return abs(self) == abs(other)
def __lt__(self, other):
return abs(self) < abs(other)
(那是你需要的所有代码。)
我希望我的包能够透明地使用内置的复杂数据类型以及numpy.complex。如何在没有代码重复的情况下优雅地完成这项工作?
当右参数是正常的复数(或任何)数时,它会自动运行:
>>> CustomComplex(1+7j) < 2+8j
True
但如果你想使用运算符<
等而不是函数,那么你可以做到最好。 complex
类型不允许您设置__lt__
并且TypeError是硬编码的。
如果要对普通complex
数字进行此类比较,则必须定义并使用自己的比较函数而不是常规运算符。或者只使用abs(a) < abs(b)
,这是明确的,并不是非常冗长。
* Timing内置abs
与numpy.abs
:
>>> timeit.timeit('abs(7+6j)')
0.10257387161254883
>>> timeit.timeit('np.abs(7+6j)', 'import numpy as np')
1.6638610363006592