为什么Python不具有符号function?

我不明白为什么Python没有signfunction。 它有一个abs内胆(我认为是她的妹妹),但没有sign

在python 2.6甚至有一个copysign函数( math ),但没有迹象。 当你写一个sign ,然后直接从abs(x) * sign(y)得到copysigncopysign(x,y)为什么还要写一个copysign(x,y) abs(x) * sign(y) ? 后者会更加清楚:x与y的符号,而与copysign,你必须记住,如果它是x的符号y或y的符号x!

很明显, sign(x)不会提供比cmp(x,0)更多的东西,但是它也会更易读(也就是像python这样的可读性很强的语言,这将会是一个很大的优势)。

如果我是一名pythondevise师,我会是另一种方式:没有cmp内置,而是一个sign 。 当你需要cmp(x,y) ,你可以做一个sign(xy) (或者,对于非数值的东西来说更好,只是ax> y – 当然这应该需要sorted接受一个布尔值而不是一个整数比较器)。 这也将更清楚:当x>y时为正数(而对于cmp ,当第一个 更大时必须记住惯例,但也可能是相反方向)。 当然,由于其他原因, cmp本身是有意义的(例如,当对非数值事物进行sorting时,或者如果您希望sorting是稳定的,那么使用布尔值是不可能的)

所以,问题是:为什么Pythondevise者决定离开语言signfunction? 为什么heck打扰copysign而不是它的父母的sign

我错过了什么吗?

编辑 – 彼得·汉森评论后。 公平的,你没有使用它,但你没有说你使用python的。 在我使用python的7年中,我需要无数次,最后是打破骆驼背的秸秆!

是的,你可以通过cmp,但是我需要通过它的90%的时间是在lambda x,y: cmp(score(x),score(y))这样的习惯用法符号。

最后,我希望你们同意这个signcopysign更有用,所以即使我买了你的观点,为什么还要在math中定义它,而不是标志? copysign如何比标志更有用?

编辑:

事实上,在math中有一个包含sign()的补丁 ,但是没有被接受,因为他们不同意在所有的边缘情况下 (+/- 0,+/- nan等)返回什么。

所以他们决定只实现copysign,它可以用来委托给最终用户期望的边缘情况 – 有时可能需要调用cmp(x,0)


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

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

最重要的是, copysign是一个sign的超集! 使用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) 

是的,我很惊讶你已经使用了7年的Python,并认为cmp可以很容易地被删除,并被sign取代! 你有没有用__cmp__方法实现一个类? 你从来没有调用cmp并指定一个自定义的比较函数?

总之,我发现自己也想要一个sign函数,但是将第一个参数copysign 1的结果是正确的。 我不同意这个signcopysign更有用,因为我已经certificate它只是同一function的一个子集。

“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中不可用的具体原因,我不知道。 我可以做出假设,但这是猜测。

math模块本身使用signbit(1,x)来检查x是负数还是非负数。 对于大多数处理math函数的情况,似乎比具有返回1,0或-1的符号(x)更有用,因为有一种情况需要考虑。 例如,下面是来自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()函数更有效的函数。

你写了:

如果我是一个Pythondevise师,我会是另一种方式:没有cmp()内置,但一个符号()

这意味着你不知道cmp()用于数字之外的事情。 cmp(“This”,“That”)不能用sign()函数实现。

编辑整理我的其他答案

你根据abs()和sign()经常在一起看到的理由。 由于C标准库不包含任何forms的“sign(x)”函数,我不知道你是如何certificate你的观点的。 有一个abs(int)和fabs(double)和fabsf(float)和fabsl(long),但没有提到符号。 有“copysign()”和“signbit()”,但这些只适用于IEEE 754号码。

复杂的数字,什么会签署(-3 + 4j)在Python中返回,是否被执行? abs(-3 + 4j)返回5.0。 这是abs()可以用在sign()没有意义的地方的一个明确的例子。

假设sign(x)被添加到Python,作为abs(x)的补充。 如果'x'是实现__abs __(self)方法的用户定义类的实例,则abs(x)将调用x .__ abs __()。 为了正确地工作,以相同的方式处理abs(x),那么Python将不得不获得符号 (x)槽。

这对于相对不必要的function来说是过度的。 此外,为什么sign(x)存在且非负(x)和非正(x)不存在? 我从Python的math模块实现的片段展示了如何使用copybit(x,y)来实现非负(),这是一个简单的符号(x)不能做到的。

Python应该支持对IEEE 754 / C99math函数的更好的支持。 这将添加一个signbit(x)函数,这将做你想要的情况下浮动。 它不适用于整数或复数,更不用说string,它不会有你正在寻找的名字。

你问“为什么”,答案是“sign(x)没有用”。 你断言它是有用的。 然而,你的评论表明,你不足以做出这样的断言,这意味着你将不得不展示其需要的令人信服的证据。 说NumPy实现它是不够的。 您需要展示如何使用符号函数来改进现有代码的情况。

而且它超出了StackOverflow的范围。 把它改为Python列表之一。

另一个符号()

 sign = lambda x: (1, -1)[x<0] 

如果你想让x = 0返回0:

 sign = lambda x: x and (1, -1)[x<0] 

由于cmp已被删除 ,您可以使用相同的function

 def cmp(a, b): return (a > b) - (a < b) def sign(a): return (a > 0) - (a < 0) 

它适用于floatint ,甚至Fraction 。 在float的情况下,通知sign(float("nan"))为零。

Python不要求比较返回一个布尔值,所以强制比较bool()可以防止允许但不常见的实现:

 def sign(a): return bool(a > 0) - bool(a < 0) 

尝试运行这个,其中x是任何数字

 int_sign = bool(x > 0) - bool(x < 0) 

对bool()的强制处理比较运算符不返回布尔值的可能性 。

numpy有一个标志function,并给你一个其他function的奖金。 所以:

 import numpy as np x = np.sign(y) 

只要小心,结果是numpy.float64:

 >>> type(np.sign(1.0)) <type 'numpy.float64'> 

对于像json这样的东西,这很重要,因为json不知道如何序列化numpy.float64types。 在这种情况下,你可以这样做:

 float(np.sign(y)) 

获得一个正常的浮动。

是的,一个正确的sign()函数应该至less在math模块中 – 因为它是numpy。 因为math导向的代码经常需要它。

但是math.copysign()也是独立有用的。

cmp()obj.__cmp__() …独立地具有普遍高的重要性。 不只是面向math的代码。 考虑比较/sorting元组,date对象,…

http://bugs.python.org/issue1640有关遗漏;math.sign()的开发参数很奇怪,因为:

  • 没有单独的-NaN
  • sign(nan) == nan无忧(像exp(nan)
  • sign(-0.0) == sign(0.0) == 0无需担心
  • sign(-inf) == -1不用担心

– 因为它是在numpy

你不需要一个,你可以使用:

 If not number == 0: sig = number/abs(number) else: sig = 0 

在Python 2中,cmp()返回一个整数:不要求结果是-1,0或1,所以sign(x)和cmp(x,0)不一样。

在Python 3中,cmp()已被删除,以便进行丰富的比较。 对于cmp(),Python 3build议( https://docs.python.org/3/whatsnew/3.0.html ):

 def cmp(a, b): return (a > b) - (a < b) 

这对于cmp()是好的,但是不能用于sign(),因为比较运算符不需要返回布尔值( https://docs.python.org/3/reference/datamodel.html#object。lt ) 。

为了处理这种可能性,比较结果必须被强制为布尔值:

  def sign(a): return bool(x > 0) - bool(x < 0) 

这适用于任何完全有序的types(包括像NaN或infinities这样的特殊值)。

不包括“签名”的原因是,如果我们在内置函数列表中包含每一个有用的单行内容,Python将不再容易和实用。 如果你经常使用这个函数,那么你为什么不把它排除在外呢? 这不是很难,甚至是乏味的。