mpmath.plot绘制lambda生成的函数时仅显示单个函数的问题咨询
mpmath.plot绘制lambda生成的函数时仅显示单个函数的问题咨询
嘿各位,我最近用mpmath.plot绘图时遇到了个奇怪的问题,想跟大家请教下。我知道mpmath的plot底层其实是调用pyplot,先给大家看我的代码:
from math import cos, sin import mpmath as mp # 这段完全没问题,sin和cos两个函数都能正常画出来 mp.plot([sin, cos], [0, 3]) l = [sin, cos] # 但这段代码运行后,居然只画出了sin(2x),cos(2x)完全没踪影 mp.plot([lambda x: f(2*x) for f in l], [0, 3])
我翻来覆去检查了代码,实在没找出哪里写错了,想问问这是我忽略了什么细节,还是mpmath.plot本身有bug呀?
问题原因&解决办法
其实这是Python里闭包延迟绑定的经典小陷阱!你在列表推导式里创建lambda的时候,lambda内部的变量f并没有在创建时就绑定当前循环的f值,而是要等到这个lambda被调用的时候,才会去查找f的当前引用。当mpmath.plot开始遍历调用这些lambda函数时,整个列表推导式的循环已经跑完了,f此时指向的是列表l的最后一个元素——这就导致两个lambda实际指向的是同一个函数,绘图时两条曲线完全重叠,看起来就像只显示了一个。
解决这个问题很简单,有两种常用方法:
方法1:给lambda添加默认参数,强制绑定当前的f值
l = [sin, cos] # 给lambda加个f=f的默认参数,创建时就把当前的f绑定进去 mp.plot([lambda x, f=f: f(2*x) for f in l], [0, 3])
方法2:用函数工厂包装,避免闭包延迟绑定
def create_scaled_func(f): # 每个函数都会绑定自己的f参数 return lambda x: f(2*x) l = [sin, cos] mp.plot([create_scaled_func(f) for f in l], [0, 3])
用这两种方法,每个缩放后的函数都会正确绑定到对应的原函数,mpmath.plot就能正常画出两个不同的曲线啦!
备注:内容来源于stack exchange,提问作者NYG
相关产品推荐
相关产品推荐

