如何让Python Lambda函数立即而非延迟计算变量
解决Bottle框架循环创建路由时的Lambda延迟绑定问题
你遇到的问题是Python中lambda的延迟绑定特性导致的:循环里定义的lambda不会立即捕获action的当前值,而是在调用时才去读取action变量的引用,此时循环已经结束,action固定为最后一个值"close"。
下面是几种可行的解决方案:
方案1:利用Lambda默认参数绑定当前值
给lambda添加一个默认参数,将当前循环的action值赋值给它。默认参数会在lambda定义时就完成计算并绑定,而非调用时:
from bottle import Bottle, request class Fridge: def _not_exposed(self): print("This one is never called via HTTP") def open(self, param1=None, param2=None): print("Open", param1, param2) def close(self): print("Close") f = Fridge() app = Bottle("") for action in ["open", "close"]: # 通过默认参数act=action,在定义时绑定当前action的值 app.route(f"/action/{action}", callback=lambda act=action: getattr(f, act)(**request.query)) app.run()
方案2:提前获取目标方法并捕获
在循环内部先获取当前action对应的Fridge方法,再让lambda捕获这个局部方法变量。由于每次循环的局部变量都是独立的,不会被后续循环覆盖:
from bottle import Bottle, request class Fridge: def _not_exposed(self): print("This one is never called via HTTP") def open(self, param1=None, param2=None): print("Open", param1, param2) def close(self): print("Close") f = Fridge() app = Bottle("") for action in ["open", "close"]: # 提前获取当前action对应的方法,存入局部变量 target_method = getattr(f, action) app.route(f"/action/{action}", callback=lambda: target_method(**request.query)) app.run()
方案3:使用functools.partial包装方法
借助functools.partial来固定方法引用,避免lambda的延迟绑定问题:
from bottle import Bottle, request from functools import partial class Fridge: def _not_exposed(self): print("This one is never called via HTTP") def open(self, param1=None, param2=None): print("Open", param1, param2) def close(self): print("Close") f = Fridge() app = Bottle("") for action in ["open", "close"]: target_method = getattr(f, action) # 用partial包装方法,后续调用时自动传入request.query参数 app.route(f"/action/{action}", callback=lambda: partial(target_method, **request.query)()) app.run()
以上三种方案都能实现你预期的效果,让每个路由正确绑定对应的Fridge方法。
内容的提问来源于stack exchange,提问作者Basj
相关产品推荐
相关产品推荐

