for 循环中使用 updater 的注意事项
Posted daxiangcai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了for 循环中使用 updater 的注意事项相关的知识,希望对你有一定的参考价值。
例如,我想让三个圆及其圆心绕着原点旋转,其中圆通过 updater 移动到圆心上:
mobs = VGroup() for i in range(3): dot = Dot() distance = 0.5 + np.random.random()*1.3 angle = np.random.random()*2*PI dot.shift([distance*np.cos(angle), distance*np.sin(angle), 0]) dot.add_updater(lambda z, dt: z.rotate(0.5*PI*dt, about_point=ORIGIN)) circle = Circle().move_to(dot) circle.add_updater(lambda z: z.move_to(dot)) mobs.add(dot, circle) self.add(mobs) self.wait(3)
但是实际上,看起来的效果好像是三个圆都围绕着同一个圆心,而不是各自的圆心
这其实是 for 循环中使用闭包而导致的,这是一个例子:
fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) f1, f2, f3 = fs print(f1(), f2(), f3())
你可能认为结果是 1, 4, 9,但实际上结果为 9, 9, 9
我的看法是,闭包的结果是返回一个函数,如果这个函数没有传入参数,那么就会产生问题。上面的例子中 f() 没有传入任何的参数,等到循环结束后,i 已经变成了 3,这时候 f1, f2, f3 其实是等价的,均返回 3*3
解决方法也很简单,只需要在 f() 中传入参数即可:
fs = [] for i in range(1, 4): def f(n): def g(): return n*n # 这里不能写成 i*i return g fs.append(f(i)) f1, f2, f3 = fs print(f1(), f2(), f3())
我们回到最初的问题,lambda 本质上也是一个函数,我们需要改写一下,使得每个 updater 的函数均绑定到各自的对象上:
mobs = VGroup() for i in range(3): def generate_updater(mob1, mob2): def updater(mob1): mob1.move_to(mob2) return updater # 这里不用传入参数 dot = Dot() distance = 0.5 + np.random.random()*1.3 angle = np.random.random()*2*PI dot.shift([distance*np.cos(angle), distance*np.sin(angle), 0]) dot.add_updater(lambda z, dt: z.rotate(0.5*PI*dt, about_point=ORIGIN)) circle = Circle().move_to(dot) circle.add_updater(generate_updater(circle, dot)) mobs.add(dot, circle) self.add(mobs) self.wait(3)
以上是关于for 循环中使用 updater 的注意事项的主要内容,如果未能解决你的问题,请参考以下文章
thinkphp中的lock与mysql的for update的使用注意事项
C++11新特性:15—— C++11 for循环使用注意事项