为什么Python不具有符号function?
我不明白为什么Python没有sign
function。 它有一个abs
内胆(我认为是她的妹妹),但没有sign
。
在python 2.6甚至有一个copysign
函数( math ),但没有迹象。 当你写一个sign
,然后直接从abs(x) * sign(y)
得到copysign
时copysign(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者决定离开语言sign
function? 为什么heck打扰copysign
而不是它的父母的sign
?
我错过了什么吗?
编辑 – 彼得·汉森评论后。 公平的,你没有使用它,但你没有说你使用python的。 在我使用python的7年中,我需要无数次,最后是打破骆驼背的秸秆!
是的,你可以通过cmp,但是我需要通过它的90%的时间是在lambda x,y: cmp(score(x),score(y))
这样的习惯用法符号。
最后,我希望你们同意这个sign
比copysign
更有用,所以即使我买了你的观点,为什么还要在math中定义它,而不是标志? copysign如何比标志更有用?
编辑:
事实上,在math中有一个包含sign()
的补丁 ,但是没有被接受,因为他们不同意在所有的边缘情况下 (+/- 0,+/- nan等)返回什么。
所以他们决定只实现copysign,它可以用来委托给最终用户期望的边缘情况 – 有时可能需要调用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)
是的,我很惊讶你已经使用了7年的Python,并认为cmp
可以很容易地被删除,并被sign
取代! 你有没有用__cmp__
方法实现一个类? 你从来没有调用cmp
并指定一个自定义的比较函数?
总之,我发现自己也想要一个sign
函数,但是将第一个参数copysign
1的结果是正确的。 我不同意这个sign
比copysign
更有用,因为我已经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)
它适用于float
, int
,甚至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将不再容易和实用。 如果你经常使用这个函数,那么你为什么不把它排除在外呢? 这不是很难,甚至是乏味的。