Why doesn't Python have a sign function?
我无法理解为什么Python没有
在python 2.6中甚至有一个
显然
如果我是一名Python设计师,我会采用另一种方式:没有
所以,问题是:为什么Python设计师决定将
我错过了什么吗?
编辑 - 在彼得汉森评论之后。
很公平,你没有使用它,但你没有说你使用python的。在我使用python的7年中,我无数次需要它,而最后一个是打破骆驼背部的稻草!
是的,你可以通过cmp,但我需要通过它的90%的时间都是成语
最后,我希望你同意
编辑:
确实有一个补丁包括数学中的
所以他们决定只实现copysign,它可以用来向最终用户委派边缘情况所需的行为(尽管更详细) - 有时可能需要调用
我不知道为什么它不是内置的,但我有一些想法。
1 2 | copysign(x,y): Return x with the sign of y. |
最重要的是,
1 2 3 4 | >>> math.copysign(1, -4) -1.0 >>> math.copysign(1, 3) 1.0 |
如果你厌倦了传递两个完整的参数,你可以用这种方式实现
1 2 3 4 5 6 7 8 9 10 11 12 | >>> sign = functools.partial(math.copysign, 1) # either of these >>> sign = lambda x: math.copysign(1, x) # two will work >>> sign(-4) -1.0 >>> sign(3) 1.0 >>> sign(0) 1.0 >>> sign(-0.0) -1.0 >>> sign(float('nan')) -1.0 |
其次,通常当你想要某些东西的符号时,你最终会将它与另一个值相乘。当然,这基本上是
所以,而不是:
1 2 | s = sign(a) b = b * s |
你可以这样做:
1 | b = copysign(b, a) |
是的,我很惊讶你已经使用Python 7年了,并认为
总之,我发现自己也想要一个
"copysign"由IEEE 754定义,是C99规范的一部分。这就是为什么它在Python中。该函数不能由abs(x)* sign(y)完全实现,因为它应该如何处理NaN值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >>> import math >>> math.copysign(1, float("nan")) 1.0 >>> math.copysign(1, float("-nan")) -1.0 >>> math.copysign(float("nan"), 1) nan >>> math.copysign(float("nan"), -1) nan >>> float("nan") * -1 nan >>> float("nan") * 1 nan >>> |
这使得copysign()比sign()更有用。
至于为什么IEEE的signbit(x)在标准Python中不可用的具体原因,我不知道。我可以做出假设,但这是猜测。
数学模块本身使用signbit(1,x)作为检查x是负还是非负的方法。对于大多数处理数学函数的情况,这些函数似乎比具有返回1,0或-1的符号(x)更有用,因为有一个案例需要考虑。例如,以下内容来自Python的数学模块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | static double m_atan2(double y, double x) { if (Py_IS_NAN(x) || Py_IS_NAN(y)) return Py_NAN; if (Py_IS_INFINITY(y)) { if (Py_IS_INFINITY(x)) { if (copysign(1., x) == 1.) /* atan2(+-inf, +inf) == +-pi/4 */ return copysign(0.25*Py_MATH_PI, y); else /* atan2(+-inf, -inf) == +-pi*3/4 */ return copysign(0.75*Py_MATH_PI, y); } /* atan2(+-inf, x) == +-pi/2 for finite x */ return copysign(0.5*Py_MATH_PI, y); |
在那里你可以清楚地看到copysign()是一个比三值sign()函数更有效的函数。
你写了:
If I were a python designer, I would been the other way arond: no cmp() builtin, but a sign()
这意味着你不知道cmp()用于数字以外的东西。 cmp("This","That")无法使用sign()函数实现。
编辑以在其他地方整理我的其他答案:
你的理由基于如何经常看到abs()和sign()。由于C标准库不包含任何类型的"sign(x)"函数,因此我不知道您如何证明您的观点。有一个abs(int)和fabs(双)和fabsf(浮动)和fabsl(长)但没有提到标志。有"copysign()"和"signbit()"但这些仅适用于IEEE 754号码。
对于复数,在Python中返回的符号(-3 + 4j)会被实现吗? abs(-3 + 4j)返回5.0。这是一个明确的例子,说明如何在sign()没有意义的地方使用abs()。
假设sign(x)被添加到Python中,作为abs(x)的补充。如果'x'是实现__abs __(self)方法的用户定义类的实例,则abs(x)将调用x .__ abs __()。为了正常工作,以相同的方式处理abs(x),Python必须获得一个符号(x)槽。
对于相对不需要的功能,这是过度的。此外,为什么签名(x)存在且非负(x)和非正(x)不存在?我的Python数学模块实现的片段显示了如何使用copybit(x,y)来实现非负(),这是一个简单的符号(x)无法做到的。
Python应该支持更好地支持IEEE 754 / C99数学函数。这将添加一个signbit(x)函数,它可以在浮点数的情况下执行您想要的操作。它不适用于整数或复数,更不用说字符串,也不会有你想要的名字。
你问"为什么",答案是"符号(x)没用"。你声称它很有用。然而,你的评论表明你不知道能够做出这样的断言,这意味着你必须展示其需要的令人信服的证据。说NumPy实现它并不足够令人信服。您需要显示如何使用sign函数改进现有代码的情况。
而且它超出了StackOverflow的范围。把它改为Python列表中的一个。
标志的另一个班轮()
1 | sign = lambda x: (1, -1)[x<0] |
如果你希望它为x = 0返回0:
1 | sign = lambda x: x and (1, -1)[x<0] |
由于
1 2 3 4 5 | def cmp(a, b): return (a > b) - (a < b) def sign(a): return (a > 0) - (a < 0) |
它适用于
Python不要求比较返回布尔值,因此强制比较bool()可以防止允许但不常见的实现:
1 2 | def sign(a): return bool(a > 0) - bool(a < 0) |
尝试运行这个,其中x是任意数字
1 | int_sign = bool(x > 0) - bool(x < 0) |
对bool()的强制处理比较运算符不返回布尔值的可能性。
只有符合维基百科定义的正确答案
维基百科上的定义如下:
因此,
1 | sign = lambda x: -1 if x < 0 else (1 if x > 0 else 0) |
此函数定义执行速度快,并为0,0.0,-0.0,-4和5产生保证的正确结果(请参阅对其他错误答案的注释)。
numpy有一个sign功能,并为你提供其他功能的奖励。所以:
1 2 | import numpy as np x = np.sign(y) |
请注意,结果是numpy.float64:
1 2 | >>> type(np.sign(1.0)) <type 'numpy.float64'> |
对于像json这样的东西,这很重要,因为json不知道如何序列化numpy.float64类型。在这种情况下,你可以这样做:
1 | float(np.sign(y)) |
获得常规浮动。
是的,正确的
但
http://bugs.python.org/issue1640关于遗漏
-
没有单独的
-NaN -
sign(nan) == nan 无需担心(如exp(nan) ) -
sign(-0.0) == sign(0.0) == 0 无需担心 -
sign(-inf) == -1 无需担心
- 因为它是numpy
在Python 2中,
在Python 3中,
1 2 | def cmp(a, b): return (a > b) - (a < b) |
这对cmp()很好,但又不能用于sign(),因为比较运算符不需要返回布尔值。
为了解决这种可能性,必须将比较结果强制为布尔值:
1 2 | def sign(a): return bool(x > 0) - bool(x < 0) |
这适用于任何完全有序的
你不需要一个,你可以使用:
1 2 3 4 | If not number == 0: sig = number/abs(number) else: sig = 0 |
不包含"符号"的原因是,如果我们在内置函数列表中包含每个有用的单行,那么Python将不再容易实用。
如果您经常使用此功能,那么为什么不自己考虑它?这样做并不是很难,甚至是单调乏味。