Python中列表推导式内Observable订阅错误对象的问题
问题分析与解决:列表推导式中Observable订阅的异常行为
问题根源:Lambda的后期绑定
你碰到的问题是Python lambda表达式的后期绑定特性导致的:在列表推导式里定义的lambda,并不会在迭代过程中捕获当前的s对象,而是要等到lambda被实际调用时,才会去查找变量s的当前值。
当列表推导式循环结束后,变量s最终指向的是列表里的最后一个对象b。所以当你调用a.update()触发回调时,lambda里的id(s)实际取的是b的ID,而x是a传入的更新值——这就造成了“更新a时b的回调被触发”的错觉,本质是a的回调函数执行时,引用了已经指向b的变量s。
解决方案:提前绑定迭代对象
有两种简单的方式可以解决这个问题,核心都是让回调函数在定义时就捕获当前迭代的s对象:
方式1:利用默认参数绑定当前值
在lambda中添加一个带默认值的参数,利用Python默认参数在函数定义时求值的特性,把当前的s绑定到参数里:
[s.subscribe(lambda x, obj=s: print(f"{id(obj)}: {x}")) for s in [a,b]]
方式2:用functools.partial绑定参数
借助functools.partial将当前的s提前绑定到回调函数的参数中:
from functools import partial def print_callback(obj, x): print(f"{id(obj)}: {x}") [s.subscribe(partial(print_callback, s)) for s in [a,b]]
验证效果
修改后执行a.update("foobar"),只会输出a的ID和新值,不会再出现b的ID,符合预期行为。
内容的提问来源于stack exchange,提问作者Fred Guth
相关产品推荐
相关产品推荐

