t /= d是什么意思?Python及错误处理

6 投票
5 回答
1342 浏览
提问于 2025-04-17 19:48
// 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 个回答

1

/= 是一种增强赋值运算符。t /= d 的意思和 t = t / d 是一样的。还有其他类似的运算符,比如 +=-=*= 等等。

1
c*(t/=d)*t + b;

这等于

t /= d            # or t = t / d
c * t * t + b

因为在Python中,不能在表达式里进行赋值

记住,如果 td 都是 int/long 类型的话,在Python2中,这将会是一个截断的除法

同样,easeOutQuad 将会是

def easeOutQuad (x, t, b, c, d):
    t /= d
    return -c * t * (t - 2) + b
7

在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的值。(你需要了解“计算”的意思,以及GetValueSetValue的含义,但我很确定这确实是有保证的。)

撰写回答