为什么 Python 没有符号函数?

新手上路,请多包涵

我不明白为什么 Python 没有 sign 函数。它有一个 abs 内置(我认为是 sign 的姐妹),但没有 sign

在 python 2.6 中甚至有一个 copysign 函数(在 math 中),但没有符号。 Why bother to write a copysign(x,y) when you could just write a sign and then get the copysign directly from abs(x) * sign(y) ?后者会更清楚:带有 y 符号的 x,而对于 copysign,您必须记住它是带有 y 符号的 x 还是带有 x 符号的 y!

显然 sign(x) 提供 cmp(x,0) ,但它也将更具可读性(对于像 python 这样可读性很强的语言,这将是一个很大的优势) .

如果我是 Python 设计师,我会反过来:没有 cmp 内置,而是 sign 。当你需要 cmp(x,y) 时,你可以做一个 sign(x-y) (或者,对于非数字的东西更好,只是 ax>y - 当然这应该需要 sorted 接受布尔值而不是整数比较器)。这也会更清楚:当 x>y 时为正(而 cmp 你必须记住约定 positive 当第 一个 更大 时,但它可能是相反的)。当然 cmp 出于其他原因(例如,在对非数字事物进行排序时,或者如果您希望排序稳定,仅使用布尔值是不可能的)

所以,问题是:为什么 Python 设计者决定将 sign 函数从语言中移除?为什么要打扰 copysign 而不是它的父 sign

我错过了什么吗?

编辑 - 在 Peter Hansen 评论之后。很公平,你没有使用它,但你没有说你使用 python 的目的。在我使用python的7年时间里,无数次需要它,而最后一次是压死骆驼的最后一根稻草!

是的,您可以传递 cmp,但我需要传递它的 90% 的时间是在像 lambda x,y: cmp(score(x),score(y)) 这样的成语中,它可以与 sign 一起工作。

最后,我希望你同意 signcopysign 更有用,所以即使我接受了你的观点,为什么还要费心用数学而不是符号来定义它? copysign 怎么能比 sign 有用这么多呢?

原文由 Davide 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 547
2 个回答

编辑:

确实有一个 补丁,其中包括 sign()数学 中,但它没有被接受,因为他们不同意 在所有边缘情况下它应该返回什么(+/-0,+/-nan , ETC)

因此,他们决定只实现 copysign,它(虽然更冗长)可 用于将边缘情况所需的行为委托给最终用户—— 有时可能需要调用 cmp(x,0)


我不知道为什么它不是内置的,但我有一些想法。

 copysign(x,y):
Return x with the sign of y.

最重要的是, copysignsign 的超集!使用 x=1 调用 copysignsign 函数相同。所以你可以只使用 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 就可以正常工作。我不同意 signcopysign 更有用,因为我已经证明它只是相同功能的一个子集。

原文由 FogleBird 发布,翻译遵循 CC BY-SA 3.0 许可协议

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() 更有用。

至于IEEE的 signbit(x) 在标准Python中不可用的具体原因,我不知道。我可以做出假设,但那只是猜测。

数学模块本身使用 copysign(1, x) 作为检查 x 是负数还是非负数的方法。 For most cases dealing with mathematical functions that seems more useful than having a sign(x) which returns 1 , 0 , or -1 because there’s one更少的情况要考虑。例如,以下来自 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) 函数,我不知道你如何证明你的观点。 There’s an abs(int) and fabs(double) and fabsf(float) and fabsl(long) but no mention of sign() .有 copysign()signbit() 但这些仅适用于 IEEE 754 号码。

对于复数,sign(-3+4j) 在 Python 中会返回什么,是否要实现? abs(-3+4j) 返回 5.0。这是一个清楚的例子,说明 abs() 可以用在 sign() 没有意义的地方。

假设 sign(x) 被添加到 Python,作为 abs(x) 的补充。 If x is an instance of a user-defined class which implements the __abs__(self) method then abs(x) will call x.__abs__() .为了正确工作,以相同的方式处理 abs(x) Python 将必须获得 __sign__(x) 插槽。

这对于相对不需要的功能来说是过多的。此外,为什么 sign(x) 存在而 nonnegative(x)nonpositive(x) 不存在?我从 Python 的数学模块实现中摘录的片段显示了 copysign(x, y) 如何用于实现 nonnegative() ,一个简单的 sign(x) 不能

Python 应该更好地支持 IEEE 754/C99 数学函数。这将添加一个 signbit(x) 函数,这将在浮动的情况下执行您想要的操作。它不适用于整数或复数,更不用说字符串了,而且它不会有您要查找的名称。

你问“为什么”,答案是“ sign(x) 。”你断言它是有用的。然而,您的评论表明您的知识还不足以做出该断言,这意味着您必须提供令人信服的证据来证明其必要性。说 NumPy 实现了它是不够有说服力的。您需要展示如何使用 sign() 函数改进现有代码的案例。

而且它超出了 StackOverflow 的范围。将它带到 Python 列表之一。

原文由 Andrew Dalke 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏