Manim中Updater函数被覆盖,仅最后更新器生效问题求助
问题根源
这是Python闭包的延迟绑定特性导致的:循环中定义的lambda函数不会立即捕获变量的当前值,而是在函数实际执行时才去查找变量的当前状态。当循环结束后,所有lambda都会引用循环变量的最后一个值,最终导致所有圆点和曲线都使用了最后一次循环的参数。
修复方案
要解决这个问题,需要让lambda在定义时就绑定当前循环的变量值,而不是等到执行时再去引用。
1. 修复径向基函数的定义
将原本的lambda函数通过默认参数绑定当前的i值,避免闭包延迟引用:
# 原代码(有问题) func = lambda x: norm.pdf(x, loc=i, scale=0.5) # 修改后 func = lambda x, loc=i: norm.pdf(x, loc=loc, scale=0.5)
2. 修复圆点的Updater函数
Updater函数会自动将Mobject本身作为第一个参数传入,无需额外传dot作为默认参数,只需确保绑定当前循环的graph即可:
# 原代码(有问题) dot_mover = lambda x=dot, graph=graph: x.move_to(graph.get_point_from_function(vt.get_value())) # 修改后 dot_mover = lambda dot, graph=graph: dot.move_to(graph.get_point_from_function(vt.get_value()))
完整修复代码
from manim import * import numpy as np from scipy.stats import norm class RDFBasis(Scene): def construct(self): axes = Axes( x_range=[0, 5, 1], y_range=[0, 1, 0.2], x_length=10, tips=False, ) axes_labels = axes.get_axis_labels() vt = ValueTracker(0) line = Line(axes.c2p(0, 1), axes.c2p(0, 0)) line.add_updater(lambda x: x.move_to(axes.c2p(vt.get_value(), 0.5))) graphs = [] dots = [] for i in np.linspace(0, 5, 5): # 绑定当前循环的i值 func = lambda x, loc=i: norm.pdf(x, loc=loc, scale=0.5) graph = axes.plot(func, color=RED) graphs.append(graph) dot = Dot() dot.move_to(graph.get_start()) # 绑定当前循环的graph,updater自动传入dot自身 dot_mover = lambda dot, graph=graph: dot.move_to(graph.get_point_from_function(vt.get_value())) dot.add_updater(dot_mover) dots.append(dot) plot = VGroup(axes, *graphs) labels = VGroup(axes_labels) self.add(plot, labels, line, *dots) self.play(vt.animate.set_value(5.0), run_time=3)
为什么DeepCopy没用?
问题的核心不是对象本身的重复,而是lambda闭包引用的变量指向了同一个内存地址。DeepCopy只能复制对象本身,无法改变闭包对变量的引用关系,因此无法解决这个问题。
内容的提问来源于stack exchange,提问作者Eric Taw
相关产品推荐
相关产品推荐

