问题:为什么Python没有符号功能?
我不明白为什么Python没有sign
功能。它有一个abs
内置的(我认为sign
是姐姐),但是没有sign
。
在python 2.6中甚至有一个copysign
函数(在math中),但是没有符号。copysign(x,y)
当您可以只写一个sign
然后copysign
直接从中获取时,为什么还要麻烦写一个abs(x) * sign(y)
?后者会更清楚:x带有y的符号,而带copysign的您必须记住它是x带有y的符号还是y带有x的符号!
显然sign(x)
,除了cmp(x,0)
,它不提供任何其他功能,但是它也将更具可读性(对于像python这样的易读性语言,这将是一个很大的优势)。
如果我是python设计人员,那么我会反过来:没有cmp
内置的,而是一个sign
。当需要时cmp(x,y)
,您可以做一个sign(x-y)
(或者,对于非数值的东西更好,只需x> y-当然,这应该要求sorted
接受布尔值而不是整数比较器)。这也将更加清晰:正时x>y
(而与cmp
你必须记住公约正值当第一是大的,但它可能是周围的其他方法)。当然cmp
,出于其他原因(例如,在对非数字事物进行排序时,或者如果您希望排序是稳定的,仅使用布尔值是不可能的),就有意义了
因此,问题是:为什么Python设计人员决定将sign
函数保留在语言之外?为什么要麻烦copysign
父母而不是父母sign
?
我想念什么吗?
编辑-Peter Hansen评论后。足够公平,您没有使用它,但是您没有说您使用python做什么。在使用python的7年中,我无数次需要它,最后一个是打破骆驼背的稻草!
是的,您可以传递cmp,但是我传递它的90%的时间是成语,这样
lambda x,y: cmp(score(x),score(y))
就可以很好地使用sign了。
最后,我希望您同意这sign
会比有用copysign
,所以即使我购买了您的视图,为什么还要在数学中定义它而不是符号呢?copysign如何比sign有用呢?
回答 0
编辑:
确实,数学中包含一个补丁,但未被接受,因为他们在所有极端情况(+/- 0,+ /-nan等)上均未达成共识。sign()
因此,他们决定仅实施copysign,尽管可以使用它(尽管更为冗长),才能将最终情况下所需的行为委托给最终用户 – 有时可能需要调用cmp(x,0)
。
我不知道为什么它不是内置的,但我有一些想法。
copysign(x,y):
Return x with the sign of y.
最重要的copysign
是,是的超集sign
!copysign
x = 1的调用与sign
函数相同。这样您就可以使用它,copysign
而不必理会它。
>>> math.copysign(1, -4)
-1.0
>>> math.copysign(1, 3)
1.0
如果您厌倦了传递两个完整的参数,则可以采用sign
这种方式实现,它仍将与其他人提到的IEEE兼容:
>>> 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
其次,通常,当您想要某物的符号时,您最终会将其乘以另一个值。当然,那基本上是什么copysign
。
因此,代替:
s = sign(a)
b = b * s
您可以这样做:
b = copysign(b, a)
是的,我很惊讶您已经使用Python 7年了,认为cmp
可以如此轻松地将其删除并替换为sign
!您是否从未使用__cmp__
方法实现类?您是否从未调用cmp
和指定自定义比较器函数?
总而言之,我发现自己也想要一个sign
函数,但是copysign
第一个参数为1就可以了。我不同意这样做sign
会比有用copysign
,因为我已经证明它只是相同功能的一部分。
回答 1
“ copysign”由IEEE 754和C99规范的一部分定义。这就是为什么它在Python中。该函数不能完全由abs(x)* sign(y)实现,因为它应该如何处理NaN值。
>>> 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()更有用。
至于为什么标准的Python中没有IEEE的signbit(x)的具体原因,我不知道。我可以做一些假设,但这是猜测。
数学模块本身使用copysign(1,x)作为检查x是负数还是非负数的方法。在大多数情况下,处理数学函数似乎比使sign(x)返回1、0或-1有用,因为要考虑的情况要少得多。例如,以下内容来自Python的math模块:
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()函数更有效。
你写了:
如果我是python设计器,那我将是另一种方式:没有内置的cmp(),但是有一个sign()
这意味着您不知道cmp()会用于数字以外的东西。cmp(“ This”,“ That”)不能通过sign()函数实现。
编辑以在其他地方整理我的其他答案:
您的辩解基于abs()和sign()经常一起出现的方式。由于C标准库不包含任何类型的’sign(x)’函数,因此我不知道您如何证明自己的观点。有一个abs(int)和fabs(double)和fabsf(float)和fabsl(long),但没有提及符号。有“ copysign()”和“ signbit()”,但它们仅适用于IEEE 754数字。
对于复数,如果要实现,sign(-3 + 4j)在Python中返回什么?abs(-3 + 4j)返回5.0。这是一个清晰的例子,说明在sign()毫无意义的地方如何使用abs()。
假设将sign(x)添加到Python,作为对abs(x)的补充。如果“ x”是实现__abs __(self)方法的用户定义类的实例,则abs(x)将调用x .__ abs __()。为了正常工作,以与Python相同的方式处理abs(x),Python将必须获得一个符号(x)插槽。
对于相对不需要的功能来说,这是过多的。此外,为什么应该有sign(x)而不存在nonnegative(x)和nonpositive(x)?我来自Python数学模块实现的代码片段显示了如何使用copybit(x,y)来实现nonnegative(),而简单的sign(x)无法做到这一点。
Python应该支持对IEEE 754 / C99数学函数的更好支持。这将添加一个signbit(x)函数,该函数将在浮点数的情况下实现您想要的功能。它不适用于整数或复数,更不用说字符串了,并且没有您要查找的名称。
您问“为什么”,答案是“ sign(x)没用”。您断言它很有用。然而,您的评论表明,您不足以提出该断言,这意味着您必须提供令人信服的证据来证明其必要性。说NumPy实现了它还不足以令人信服。您将需要展示如何使用符号函数改进现有代码的案例。
而且它超出了StackOverflow的范围。将其改为Python列表之一。
回答 2
另一个衬里的sign()
sign = lambda x: (1, -1)[x<0]
如果您希望它在x = 0时返回0:
sign = lambda x: x and (1, -1)[x<0]
回答 3
由于cmp
已删除,因此您可以获得与
def cmp(a, b):
return (a > b) - (a < b)
def sign(a):
return (a > 0) - (a < 0)
它的工作原理为float
,int
甚至Fraction
。对于float
,注意sign(float("nan"))
为零。
Python不需要比较返回布尔值,因此将比较强制为bool()可以避免允许的但不常见的实现:
def sign(a):
return bool(a > 0) - bool(a < 0)
回答 4
仅符合Wikipedia定义的正确答案
因此,
sign = lambda x: -1 if x < 0 else (1 if x > 0 else (0 if x == 0 else NaN))
出于所有意图和目的,可以简化为:
sign = lambda x: -1 if x < 0 else (1 if x > 0 else 0)
该函数定义执行速度很快,并保证输出0、0.0,-0.0,-4和5的正确结果(请参见其他错误答案的注释)。
请注意,零(0)既不是正数也不是负数。
回答 5
numpy具有符号功能,并且还为您提供其他功能的加成。所以:
import numpy as np
x = np.sign(y)
请注意结果是numpy.float64:
>>> type(np.sign(1.0))
<type 'numpy.float64'>
对于json之类的东西,这很重要,因为json不知道如何序列化numpy.float64类型。在这种情况下,您可以执行以下操作:
float(np.sign(y))
获得定期浮动。
回答 6
回答 7
是的,正确的sign()
函数至少应该在math模块中-就像在numpy中一样。因为一个人经常需要面向数学的代码。
但math.copysign()
也可以独立使用。
cmp()
和obj.__cmp__()
…通常独立地具有很高的重要性。不只是面向数学的代码。考虑比较/排序元组,日期对象,…
http://bugs.python.org/issue1640上关于省略的开发参数math.sign()
很奇怪,因为:
- 没有单独的
-NaN
sign(nan) == nan
不用担心(如exp(nan)
)sign(-0.0) == sign(0.0) == 0
不用担心sign(-inf) == -1
不用担心
-因为它在numpy中
回答 8
在Python 2中,cmp()
返回一个整数:不需要结果为-1、0或1,因此sign(x)
与并不相同cmp(x,0)
。
在Python 3中,cmp()
已删除它,以进行丰富的比较。对于cmp()
,Python 3 建议这样做:
def cmp(a, b):
return (a > b) - (a < b)
这对cmp()很好,但是又不能用于sign(),因为比较运算符不需要返回booleans。
为了解决这种可能性,必须将比较结果强制为布尔值:
def sign(a):
return bool(x > 0) - bool(x < 0)
这适用于所有type
完全有序的(包括特殊值,例如NaN
infinies)。
回答 9
您不需要一个,您可以使用:
If not number == 0:
sig = number/abs(number)
else:
sig = 0
回答 10
只是没有。
解决此问题的最佳方法是:
sign = lambda x: bool(x > 0) - bool(x < 0)
回答 11
之所以没有包含“符号”,是因为如果我们在内置函数列表中包含所有有用的单行代码,那么使用Python就会变得不那么容易和实用。如果您经常使用此功能,那么为什么不自己考虑呢?这样做并不难,甚至乏味。