如何在 Python 循环中断言 pyDatalog 谓词事实?
结论
可以在循环中调用 pyDatalog.assert_fact() 添加事实,例如 pyDatalog.assert_fact('Flagged', row_idx, col_idx)。这样就不必在 Python 代码中直接引用 Flagged(...),也能避免因当前作用域未定义该谓词而触发 NameError。
在这个网格中,大于 5 的值位于 (0, 1)、(1, 2)、(2, 0) 和 (2, 2)。行列下标从 0 开始。
在循环中添加事实
from pyDatalog import pyDatalog
grid = [[1, 8, 3], [4, 5, 6], [7, 2, 9]]
t = 5
for row_idx, row in enumerate(grid):
for col_idx, value in enumerate(row):
if value > t:
pyDatalog.assert_fact('Flagged', row_idx, col_idx)
result = pyDatalog.ask('Flagged(X, Y)')
print(result)
assert_fact() 接收谓词名称字符串和事实参数。上面的循环会添加 Flagged(0, 1)、Flagged(1, 2)、Flagged(2, 0) 和 Flagged(2, 2) 这几条事实。ask() 返回与查询匹配的结果。结果是集合,因此显示顺序可能不同。
使用 + Flagged(...) 的情况
也可以使用 pyDatalog 的加号语法。执行这条语句时,Flagged 必须已在当前 Python 命名空间中绑定为 pyDatalog 谓词。pyDatalog.create_terms('Flagged') 会在调用处创建这个名称。如果创建和使用发生在不同的作用域或模块中,使用处可能找不到 Flagged,并因此触发 NameError。
确认创建和使用处位于同一命名空间后,可以先创建谓词和查询变量,再运行循环:
from pyDatalog import pyDatalog
pyDatalog.create_terms('Flagged, X, Y')
grid = [[1, 8, 3], [4, 5, 6], [7, 2, 9]]
t = 5
for row_idx, row in enumerate(grid):
for col_idx, value in enumerate(row):
if value > t:
+ Flagged(row_idx, col_idx)
print(Flagged(X, Y))
原示例的代码片段还需要补齐 for 和 if 代码块的缩进。Python 的普通 for 循环不会创建新的局部作用域。如果已经在同一模块作用域执行 create_terms(),仍然遇到这个错误,可以检查实际代码是否在函数、另一个模块或不同的执行环境中创建和使用谓词。
注意事项
通过字符串名称动态添加事实时,可以使用 assert_fact()。使用 + Flagged(...) 语法时,要确保谓词名称和查询变量在调用位置可见。遍历网格时,也可以用 len(grid) 和 len(row) 处理行列数不同的网格。
备注:内容仅供参考。
