PAYATHON 2026

如何在 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) 处理行列数不同的网格。

备注:内容仅供参考。