t /= d是什么意思?Python及错误处理
// t: current time, b: begInnIng value, c: change In value, d: duration
def: 'easeOutQuad',
swing: function (x, t, b, c, d) {
//alert(jQuery.easing.default);
return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
},
easeInQuad: function (x, t, b, c, d) {
return c*(t/=d)*t + b;
},
easeOutQuad: function (x, t, b, c, d) {
return -c *(t/=d)*(t-2) + b;
},
我正在尝试把Robert Penner的缓动函数转换成Python代码,但遇到了一些困难!有没有人能帮帮我,或者之前有人做过这个吗?
https://github.com/danro/jquery-easing/blob/master/jquery.easing.js
5 个回答
/=
是一种增强赋值运算符。t /= d
的意思和 t = t / d
是一样的。还有其他类似的运算符,比如 +=
、-=
和 *=
等等。
c*(t/=d)*t + b;
这等于
t /= d # or t = t / d
c * t * t + b
因为在Python中,不能在表达式里进行赋值
记住,如果 t
和 d
都是 int
/long
类型的话,在Python2中,这将会是一个截断的除法
同样,easeOutQuad
将会是
def easeOutQuad (x, t, b, c, d):
t /= d
return -c * t * (t - 2) + b
在JavaScript和Python中,/=
是一个“增强赋值”运算符,意思差不多是一样的。
在JavaScript中:
var i = 10;
i /= 2;
…相当于:
var i = 10;
i = i / 2;
而在Python中:
i = 10
i /= 2
…同样相当于(虽然不完全一样,但对于数字来说差不多):
i = 10
i = i / 2
不过,有一个很大的不同。
在JavaScript中,赋值是一个表达式——它有一个值,这个值就是被赋给变量的值。所以:
var i = 10;
var j = i /= 2;
…大致相当于:
var i = 10;
i /= 2;
var j = i;
在Python中,赋值是一个语句。它没有值,不能在表达式中使用。所以:
i = 10
j = i /= 2
…会引发一个SyntaxError
错误。
如果你想把使用赋值(增强赋值或其他)放在表达式中间的代码移植到其他地方,通常需要把这个表达式拆成多行,或者找到一种方法重写这个表达式,使其不需要任何赋值。(但通常,这并不是坏事,因为原来的表达式本来就不太容易读…)
例如,假设JS是从左到右计算操作数的(我不确定这是否有保证):
def easeInQuad(x, t, b, c, d):
t /= d
return c*t*t+b
更一般地,你可以这样做:
old_t = t
t /= d
然后在t/=d
之前的任何t
实例替换成old_t
,而t/=d
及之后的实例保持不变。幸运的是,在这个例子中,没有之前的实例,所以我们不需要那个old_t
的东西。
如果你仔细想想,你可以用以下任何一种方式,在一行内更清晰地实现同样的效果,而不需要改变t
:
return c * (t/d) * (t/d) + b
return c * (t/d)**2 + b
return c * t*t / d*d + b
有些认为C语言的人会立刻抱怨这些“太慢”了。毕竟,第一个多做了一次除法,第二个用指数运算代替了乘法,而第三个做了两次乘法而不是一次。真可怕!
当然,你总是可以使用一个临时变量:
t_over_d = t/d
return c * t_over_d * t_over_d + b
…但对于C程序员来说,这意味着你在使用一个宝贵的寄存器。当然,任何在1985年后编写的编译器都会在t_over_d
出现后检测到t
已经不再使用,并重用同一个寄存器,但如果我们能强制它重用寄存器,尤其是如果这样能省下几次按键,为什么不呢?
在JS或Python中,乘法的成本只是调用函数、解释字节码等成本的一小部分,你根本不会注意到。而重新绑定一个局部变量的成本(尤其是在V8风格或PyPy风格的即时编译器中)可能远远高于传递一个无名临时结果的成本。
所以,这就是一个典型的错误“优化”案例,让代码变得更难理解,同时可能还让代码变慢,而这个地方根本不可能是值得优化的瓶颈。
既然gnibbler提到了JavaScript是否真的保证这个计算顺序…
首先,JavaScript的定义实际上是“Firefox的行为”(还有“Spidermonkey的行为”,但这应该是一样的——如果不一样,那JavaScript就做了两件事,所以这就更好了,对吧?)。但是ECMAScript是由标准定义的,正是这些标准让每个JS实现(尽管名字如此)都得遵循,我们可以假装ECMAScript 5.1是所有实现都遵循的标准(只要“所有实现”意味着“Opera”就行)。你可以在这里找到它。
所以,在ES 5.1中:11.5 乘法运算符保证(t/=d)
的结果会在t
之前计算,而11.13.2 复合赋值保证在完成t/=d
之前会设置t
的值。(你需要了解“计算”的意思,以及GetValue
和SetValue
的含义,但我很确定这确实是有保证的。)