Dav*_*ide 217 python language-design
我无法理解为什么Python没有sign函数.它有一个abs内置(我认为sign是它的妹妹),但没有sign.
在python 2.6中甚至有一个copysign函数(在数学中),但没有符号.copysign(x,y)当你只能写一个sign然后copysign直接从中获取时,为什么还要写一个abs(x) * sign(y)?后者会更加清晰:x带有y的符号,而对于copysign,你必须记住它的x是否带有y或y的符号,带有x的符号!
显然sign(x)不提供任何东西cmp(x,0),但它也会更具可读性(对于像python这样的高可读性语言,这本来是一个很大的优点).
如果我是一名蟒蛇设计师,那我就是另一种方式:没有cmp内置,而是一个sign.当你需要时cmp(x,y),你可以做一个sign(x-y)(或者,甚至更好的非数字的东西,只是一个x> y - 当然这应该需要sorted接受一个布尔而不是一个整数比较器).这也将更加清晰:正时x>y(而与cmp你必须记住公约正值当第一个是大,但它可能是周围的其他方式).当然cmp,由于其他原因(例如,在排序非数字事物时,或者如果您希望排序稳定,这是不可能使用简单的布尔值)
所以,问题是:为什么Python设计师决定将该sign功能从语言中删除?为什么麻烦copysign而不是它的父母sign呢?
我错过了什么吗?
编辑 - 在彼得汉森评论之后.很公平,你没有使用它,但你没有说你使用python的.在我使用蟒蛇的7年中,我无数次需要它,最后一根是打破骆驼背部的稻草!
是的,你可以通过cmp,但是我需要通过它的90%的时间都是这样的成语,就像
lambda x,y: cmp(score(x),score(y))用标志就好了.
最后,我希望你同意这sign会比这更有用copysign,所以即使我买了你的观点,为什么还要在数学中定义它而不是标志呢?copysign如何比签名更有用?
Fog*_*ird 212
编辑:
确实有一个补丁包含sign()在数学中,但它没有被接受,因为他们不同意它应该在所有边缘情况下返回什么(+/- 0,+/ - nan等)
所以他们决定只实现copysign,它可以用来向最终用户委托边缘情况所需的行为(虽然更冗长),这有时可能需要调用cmp(x,0).
我不知道为什么它不是内置的,但我有一些想法.
copysign(x,y):
Return x with the sign of y.
Run Code Online (Sandbox Code Playgroud)
最重要的copysign是,是超集sign!copysign使用x = 1 调用与sign函数相同.所以你可以使用copysign并忘记它.
>>> math.copysign(1, -4)
-1.0
>>> math.copysign(1, 3)
1.0
Run Code Online (Sandbox Code Playgroud)
如果您厌倦了传递两个完整的参数,您可以实现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
Run Code Online (Sandbox Code Playgroud)
其次,通常当你想要某些东西的符号时,你最终会将它与另一个值相乘.当然,这基本上是copysign做什么的.
所以,而不是:
s = sign(a)
b = b * s
Run Code Online (Sandbox Code Playgroud)
你可以这样做:
b = copysign(b, a)
Run Code Online (Sandbox Code Playgroud)
是的,我很惊讶你已经使用Python 7年了,并且认为cmp可以很容易地删除并替换为sign!你有没有用__cmp__方法实现一个类?您是否从未调用过cmp并指定了自定义比较器功能?
总而言之,我发现自己也想要一个sign函数,但是copysign第一个参数为1将会正常工作.我不同意这sign比有用的更有用copysign,因为我已经表明它只是相同功能的一个子集.
And*_*lke 56
"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
>>>
Run Code Online (Sandbox Code Playgroud)
这使得copysign()比sign()更有用.
至于为什么IEEE的signbit(x)在标准Python中不可用的具体原因,我不知道.我可以做出假设,但这是猜测.
数学模块本身使用signbit(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);
Run Code Online (Sandbox Code Playgroud)
在那里你可以清楚地看到copysign()是一个比三值sign()函数更有效的函数.
你写了:
如果我是一名python设计师,我就会采用另一种方式:没有内置的cmp(),而是一个符号()
这意味着你不知道cmp()用于数字以外的东西.cmp("This","That")无法使用sign()函数实现.
编辑以在其他地方整理我的其他答案:
你的理由基于如何经常看到abs()和sign().由于C标准库不包含任何类型的"sign(x)"函数,因此我不知道您如何证明您的观点.有一个abs(int)和fabs(双)和fabsf(浮动)和fabsl(长)但没有提到标志.有"copysign()"和"signbit()"但这些仅适用于IEEE 754号码.
对于复数,在Python中返回的符号(-3 + 4j)会被实现吗?abs(-3 + 4j)返回5.0.这是一个明确的例子,说明如何在sign()没有意义的地方使用abs().
假设sign(x)被添加到Python中,作为abs(x)的补充.如果'x'是实现__abs __(self)方法的用户定义类的实例,则abs(x)将调用x .__ abs __().为了正常工作,以相同的方式处理abs(x),Python必须获得一个符号(x)槽.
对于相对不需要的功能,这是过度的.此外,为什么签名(x)存在且非负(x)和非正(x)不存在?我的Python数学模块实现的片段显示了如何使用copybit(x,y)来实现非负(),这是一个简单的符号(x)无法做到的.
Python应该支持更好地支持IEEE 754/C99数学函数.这将添加一个signbit(x)函数,它可以在浮点数的情况下执行您想要的操作.它不适用于整数或复数,更不用说字符串,也不会有你想要的名字.
你问"为什么",答案是"符号(x)没用".你声称它很有用.然而,你的评论表明你不知道能够做出这样的断言,这意味着你必须展示其需要的令人信服的证据.说NumPy实现它并不足够令人信服.您需要显示如何使用sign函数改进现有代码的情况.
而且它超出了StackOverflow的范围.把它改为Python列表中的一个.
dan*_*lmo 31
标志的另一个班轮()
sign = lambda x: (1, -1)[x<0]
Run Code Online (Sandbox Code Playgroud)
如果你希望它为x = 0返回0:
sign = lambda x: x and (1, -1)[x<0]
Run Code Online (Sandbox Code Playgroud)
小智 22
由于cmp已被删除,您可以获得相同的功能
def cmp(a, b):
return (a > b) - (a < b)
def sign(a):
return (a > 0) - (a < 0)
Run Code Online (Sandbox Code Playgroud)
它适用于float,int甚至Fraction.在这种情况下float,通知sign(float("nan"))是零.
Python不要求比较返回布尔值,因此强制比较bool()可以防止允许但不常见的实现:
def sign(a):
return bool(a > 0) - bool(a < 0)
Run Code Online (Sandbox Code Playgroud)
Ser*_*ndt 10
因此,
sign = lambda x: -1 if x < 0 else (1 if x > 0 else (0 if x == 0 else NaN))
Run Code Online (Sandbox Code Playgroud)
出于所有意图和目的,可以简化为:
sign = lambda x: -1 if x < 0 else (1 if x > 0 else 0)
Run Code Online (Sandbox Code Playgroud)
此函数定义执行速度很快,并能确保为0、0.0,-0.0,-4和5提供正确的结果(请参见其他错误答案的注释)。
请注意,零(0)既不是正数也不是负数。
numpy有一个sign功能,并为你提供其他功能的奖励.所以:
import numpy as np
x = np.sign(y)
Run Code Online (Sandbox Code Playgroud)
请注意,结果是numpy.float64:
>>> type(np.sign(1.0))
<type 'numpy.float64'>
Run Code Online (Sandbox Code Playgroud)
对于像json这样的东西,这很重要,因为json不知道如何序列化numpy.float64类型.在这种情况下,您可以这样做:
float(np.sign(y))
Run Code Online (Sandbox Code Playgroud)
获得常规浮动.
小智 7
尝试运行它,其中x是任意数字
int_sign = bool(x > 0) - bool(x < 0)
Run Code Online (Sandbox Code Playgroud)
对bool()的强制处理比较运算符不返回布尔值的可能性.
是的,正确的sign()函数应该至少在 math 模块中——就像在 numpy. 因为人们经常需要它来编写面向数学的代码。
但math.copysign()也可以独立使用。
cmp()并且obj.__cmp__()……通常独立地具有很高的重要性。不仅仅是面向数学的代码。考虑比较/排序元组、日期对象……
http://bugs.python.org/issue1640 上关于省略的开发参数math.sign()很奇怪,因为:
-NaNsign(nan) == nan 不用担心(比如exp(nan))sign(-0.0) == sign(0.0) == 0 不用担心sign(-inf) == -1 不用担心-- 因为它在 numpy 中
在 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)
Run Code Online (Sandbox Code Playgroud)
这对 cmp() 很好,但同样不能用于 sign() 因为比较运算符不需要返回booleans。
为了处理这种可能性,必须将比较结果强制转换为布尔值:
def sign(x):
return bool(x > 0) - bool(x < 0)
Run Code Online (Sandbox Code Playgroud)
这适用于任何type完全有序的(包括特殊值,如NaN或无穷大)。
它只是没有。
解决此问题的最佳方法是:
sign = lambda x: bool(x > 0) - bool(x < 0)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
120742 次 |
| 最近记录: |