我不明白为什么Python没有sign
函数。它有一个内置的abs
(我认为它是sign
的姊妹),但没有sign
。
在Python2.6中,甚至有一个copysign
函数(在math中),但是没有符号。既然只需编写copysign(x,y)
,然后直接从abs(x) * sign(y)
获取copysign
,为什么还要费心编写sign
呢?后者会更清楚:x的符号是y,而使用copysign时,你必须记住是x的符号是y,还是y的符号是x!
显然,除了cmp(x,0)
之外,sign(x)
并没有提供更多的东西,但它的可读性也会更好(对于像python这样可读性很强的语言来说,这将是一个很大的优势)。
如果我是一个python设计者,我会是另一种方式:没有cmp
内置,而是一个sign
。当你需要cmp(x,y)
时,你可以只做一个sign(x-y)
(或者,对于非数字的东西,更好的是,只做一个x>y -当然这应该要求sorted
接受一个布尔值而不是整数比较器)。这也会更清楚:当x>y
时为正(而对于cmp
,当first更大时,您必须记住约定为正,但也可能是相反的情况)。当然,出于其他原因,cmp
本身也是有意义的(例如,当对非数字对象进行排序时,或者如果您希望排序是稳定的,而这不可能简单地与布尔值一起使用)。
因此,问题是:为什么Python设计者决定将sign
函数排除在语言之外?为什么要为copysign
而不是它的父sign
而烦恼呢
我是不是遗漏了什么?
编辑-在Peter Hansen评论之后。你没有使用它是合理的,但是你没有说你使用python做什么。在我使用python的7年中,我无数次地需要它,最后一次是压垮了骆驼的稻草!
是的,你可以到处传递cmp,但我需要传递它的90%的次数是在像lambda x,y: cmp(score(x),score(y))
这样的习惯用法中,它可以很好地与sign一起工作。
最后,我希望您同意sign
将比copysign
更有用,所以即使我同意您的观点,为什么还要费心在数学中定义它,而不是符号呢?为什么版权签名比签名更有用呢?
发布于 2010-01-01 03:25:01
编辑:
确实有一个patch在math中包含了sign()
,但它没有被接受,因为他们在what it should return in all the edge cases (+/-0,+/-nan等)上没有达成一致。
因此他们决定只实现copysign,它(虽然更冗长)可以是used to delegate to the end user the desired behavior for edge cases - they sometimes might require the call to cmp(x,0)
。
我不知道为什么它不是内置的,但我有一些想法。
copysign(x,y):
Return x with the sign of y.
最重要的是,copysign
是sign
的超集!使用x=1调用copysign
与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)
是的,我很惊讶你已经使用Python7年了,并且认为cmp
可以如此容易地被sign
移除并取代!您是否从未使用__cmp__
方法实现过类?您是否从未调用过cmp
并指定了自定义比较器函数?
总之,我发现自己也需要一个sign
函数,但是第一个参数为1的copysign
就可以很好地工作了。我不同意sign
会比copysign
更有用的说法,因为我已经证明了它只是相同功能的一个子集。
发布于 2010-01-01 03:12:12
“版权签名”是由IEEE754定义的,是C99规范的一部分。这就是它为什么用Python编写的原因。该函数不能完全由abs(x) * NaN (Y)实现,因为它应该如何处理符号的值。
>>> 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中不可用的具体原因,我不知道。我可以做一些假设,但这只是猜测。
数学模块本身使用copysign(1,x)作为检查x是负数还是非负数的一种方法。对于大多数情况,处理数学函数似乎比使用返回1、0或-1的符号(X)更有用,因为需要考虑的情况少了一种。例如,以下代码来自Python的数学模块:
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()内置,而是一个符号()
这意味着您不知道cmp()除了用于数字之外还有其他用途。cmp("This","That")不能用sign()函数实现。
用于整理我在其他地方的其他答案的编辑
您的理由是abs()和sign()经常被放在一起看。由于C标准库不包含任何类型的“sign(X)”函数,我不知道您如何证明您的观点是正确的。有abs(整型)、fabs(双精度)、fabsf(浮点型)和fabsl(长型),但没有提到符号。有"copysign()“和"signbit()”,但它们只适用于IEEE754号。
对于复数,sign(-3+4j)在Python语言中会返回什么,要实现它吗?abs(-3+4j)回报率为5.0.这是一个清楚的例子,说明了如何在sign()没有意义的地方使用abs()。
假设将sign(x)添加到Python中,作为abs(x)的补充。如果'x‘是实现__abs__(self)方法的用户定义类的实例,则abs(x)将调用x.__abs__()。为了正确地工作,要以同样的方式处理abs(x),那么Python将不得不获得一个sign(x)插槽。
对于相对不需要的函数来说,这是多余的。此外,为什么符号(X)存在而非负(X)和非正(X)不存在?我的Python数学模块实现片段展示了如何使用copybit(x,y)来实现非负(),这是简单的符号(X)所不能做到的。
Python应该支持对IEEE754/C99数学函数有更好的支持。这将添加一个signbit(x)函数,它将在浮点数的情况下执行您想要的操作。它不适用于整数或复数,更不用说字符串了,而且它也不会有您想要的名称。
你问“为什么”,答案是"sign(x)没有用“。你断言它是有用的。然而,你的评论表明,你知道的还不足以做出这样的断言,这意味着你必须拿出令人信服的证据来证明它的必要性。说NumPy实现了它是不够令人信服的。您需要展示如何使用sign函数改进现有代码的案例。
而且它超出了StackOverflow的范围。取而代之的是其中一个Python列表。
发布于 2013-05-24 09:37:40
sign()的另一行代码
sign = lambda x: (1, -1)[x<0]
如果您希望x=0时返回0:
sign = lambda x: x and (1, -1)[x<0]
https://stackoverflow.com/questions/1986152
复制相似问题