python-constraint循环添加约束返回空结果的问题排查
问题原因与解决方案
核心问题:Lambda闭包的延迟绑定
你代码里的问题出在循环中定义lambda约束时的闭包延迟绑定。Python的lambda表达式在定义时不会立即捕获person变量的值,而是在实际执行时才去查找person的当前值。当循环结束后,所有添加的lambda约束都会引用循环最后一次迭代的person对象,也就是["tom", "3:00"]。
所以当你调用my_function([["bob", "2:00"], ["tom", "3:00"]])时,实际添加的两个约束是:
- 对
t_bob:检查x == "3:00" - 对
t_tom:检查x == "3:00"
再加上AllDifferentConstraint要求两个时间必须不同,这就导致没有符合条件的解,返回空列表。而当只传一个元素时,循环只执行一次,lambda能正确捕获到对应的值,所以结果正常。
修复方案
解决这个问题的关键是让lambda在定义时就捕获当前迭代的person值,有两种常用方法:
方法1:使用默认参数绑定当前值
修改循环内的lambda定义,通过默认参数把当前person[1]的值绑定进去:
for person in List: problem.addConstraint( (lambda x, target=person[1]: x == target), ["t_" + person[0]] )
默认参数会在lambda定义时就计算并保存当前person[1]的值,避免后续循环修改带来的影响。
方法2:使用工厂函数生成lambda
如果觉得默认参数不够直观,可以写一个小的工厂函数来生成约束函数:
def create_constraint(target_time): return lambda x: x == target_time for person in List: problem.addConstraint( create_constraint(person[1]), ["t_" + person[0]] )
每次循环调用create_constraint时,都会把当前的person[1]作为参数传入,生成一个绑定了该值的lambda函数。
修复后的完整代码
def my_function(List): from constraint import Problem, AllDifferentConstraint problem = Problem() people = ["bob", "tom"] times = ["2:00", "3:00"] t_vars = list(map(lambda x: "t_" + x, people)) problem.addVariables(t_vars, times) problem.addConstraint(AllDifferentConstraint(), t_vars) # 使用默认参数修复闭包问题 for person in List: problem.addConstraint( (lambda x, target=person[1]: x == target), ["t_" + person[0]] ) return problem.getSolutions()
现在调用my_function([["bob", "2:00"], ["tom", "3:00"]])就能得到预期结果[{'t_bob': '2:00', 't_tom': '3:00'}]了。
内容的提问来源于stack exchange,提问作者MrWhiteee
相关产品推荐
相关产品推荐

