OptaPy Python版isEqual语法使用及get_id调用TypeError报错咨询
问题原因
你触发的TypeError: get_id() missing 1 required positional argument: 'self'错误,是因为在Joiners.equal()中直接调用了实例方法Timeslot.get_id():实例方法必须绑定到具体对象才能调用,你直接写带括号的get_id()属于未绑定调用,缺少实例参数self。
OptaPy的Joiners.equal()接收的是字段访问器函数,不需要你主动调用方法,只需要传入方法引用或者lambda表达式即可。
修正方案
方案1(无需修改Domain代码)
直接在Joiner中使用lambda表达式取值,调整constraints.py代码如下:
import datetime from optapy.score import HardSoftScore from optapy.constraint import Joiners # 替换为你实际的domain导入路径 from domain import Timeslot, Match def fill_pitches_from_start(constraint_factory): # 场地应尽可能不闲置,优先排早时段 return constraint_factory \ .forEach(Timeslot) \ .ifNotExists(Match, Joiners.equal( Timeslot.get_id, lambda match: match.timeslot.id if match.timeslot is not None else None )) \ .join(Timeslot, # 把时间比较挪到Join条件中,比事后filter效率更高 Joiners.greaterThan( lambda slot2: datetime.datetime.combine( # 替换为你实际的date_str格式 datetime.datetime.strptime(slot2.date_str, '%Y-%m-%d').date(), slot2.start_time ), lambda slot1: datetime.datetime.combine( datetime.datetime.strptime(slot1.date_str, '%Y-%m-%d').date(), slot1.start_time ) ) ) \ .ifExists(Match, Joiners.equal( lambda slot2: slot2.get_id(), lambda match: match.timeslot.id if match.timeslot is not None else None )) \ .penalize("Pitch Empty with Later pitches populated", HardSoftScore.ofSoft(10))
如果你的OptaPy版本较低不支持forEach,将其替换为旧版写法from_即可。
方案2(修改Domain代码简化约束写法)
先给Match类补充返回关联时段ID的方法:
@planning_entity class Match: # 保留你原有的__init__、规划变量定义等代码 def get_timeslot_id(self): return self.timeslot.id if self.timeslot else None
之后约束中的Joiner可以直接传方法引用,更简洁:
Joiners.equal(Timeslot.get_id, Match.get_timeslot_id)
关键改动说明
- 所有
Joiners.equal中传入的方法都去掉了括号,直接传方法引用Timeslot.get_id,OptaPy会自动把匹配到的实例传入方法获取对应值 - 修正了Match和Timeslot的匹配逻辑:直接取Match关联时段的ID和Timeslot的ID做等值匹配,避免类型不一致问题
- 补充了字符串日期转date对象的逻辑,适配
datetime.combine的参数要求,可根据你实际的date_str格式调整解析模板 - 修正了原代码中
slot1.timeslot.start_time的错误写法:slot1本身就是Timeslot实例,不需要再取.timeslot属性
内容的提问来源于stack exchange,提问作者Hebbs
相关产品推荐
相关产品推荐

