这章回答:同一个具名 Host 函数,面对独立读取、数据依赖、分支、错误和循环时,Python 程序把什么结果交给 Runner?
调用者是 CLI 或示例测试;初始状态由 inputs 和 Host 的 demoTools() 提供,Python 通过 lookup(key=...) 取值,最后把 result 交给 Guest bootstrap 编码。下面的代码块全部由 source marker 从当前文件提取,不在讲义中另写一份示例实现。
1. 最小独立读取:lookup.py
examples/lookup.py · L1–L2 · 打开完整源码
price = lookup(key=inputs["item"])
result = {"item": inputs["item"], "total": price * inputs["quantity"]}
第一行用输入中的 item 查询价格,第二行只在 Python 内做乘法并组装结果。以 book 和数量 2 为例,Host 返回 21,结果是 {"item":"book","total":42}。这是一条最短的“输入 → 具名函数 → 计算 → result”路径。
2. 两次独立查询:order.py
examples/order.py · L1–L3 · 打开完整源码
price = lookup(key=inputs["item"])
shipping = lookup(key="shipping")
result = {"item": inputs["item"], "total": price * inputs["quantity"] + shipping}
这里把商品价格和运费分成两次调用:price 使用输入的 item,shipping 使用固定 key。两次返回后,第三行计算 price * quantity + shipping。默认的 book 局面得到 21、5 和总价 47。
这个文件也是 函数流程入口 的主例子。阅读时先跟 price 和 shipping 如何进入 Host,再看第三行为什么只在 Python 侧计算;不要把结果 47 误认为外部订单或支付动作。
3. 数据依赖:dependency.py
examples/dependency.py · L1–L4 · 打开完整源码
key = lookup(key="choose")
price = lookup(key=key)
shipping = lookup(key="shipping")
result = {"item": key, "total": price * inputs["quantity"] + shipping}
第一步先查询 choose,得到商品 key;第二步把这个运行时得到的 key 传给下一次 lookup;第三步再查运费。第二次调用的参数依赖第一次的结果,因此程序的控制和数据交接要保留在原调用处。最后结果使用实际选中的 key,而不是初始输入中的 item。
4. 分支决定是否查询:branch.py
examples/branch.py · L1–L6 · 打开完整源码
price = lookup(key=inputs["item"])
if inputs["delivery"]:
shipping = lookup(key="shipping")
else:
shipping = 0
result = price * inputs["quantity"] + shipping
先读取价格,再由 inputs["delivery"] 选择是否查询运费。delivery 为真时,Host 返回 shipping;为假时,Python 直接把 shipping 设为 0。最终总价始终在同一行计算。这个例子适合对照 PLM:可以提前观察的读取不等于可以跳过条件,更不能让未走到的分支产生一次调用。
5. 捕获 Host 错误:error_delivery.py
examples/error_delivery.py · L1–L5 · 打开完整源码
try:
price = lookup(key=inputs["item"])
missing = lookup(key="absent")
except RuntimeError:
result = {"price": price, "caught": True}
price 成功后,第二次查询故意使用不存在的 key。Host 错误被 Python 的 except RuntimeError 捕获,程序把已经得到的价格和 caught: True 组成结果。正常错误交付因此停在 Python 的异常处理路径,而不是让整个 Run 直接失败。
这个小程序也说明了状态交接:price 在 try 块中赋值成功,所以捕获阶段仍能读取它;missing 没有成功赋值,也不参与结果。
6. 循环累加:fallback.py
examples/fallback.py · L1–L4 · 打开完整源码
total = 0
for key in ["book", "pen"]:
total = total + lookup(key=key)
result = total
程序从 0 开始,依次用 book 和 pen 调用具名 lookup,把两个返回值相加,最后交付 24。循环体里的 key 来自当前迭代,而不是固定的字面量;这让读者能看到“多次同一函数调用”与最终累计状态的关系。
把六个例子放回执行链
inputs + Manifest 中的具名 Python 函数
→ Guest 执行源文件
→ lookup(...) 必要时跨到 Host
→ Python 保留依赖、分支、异常或循环状态
→ result 编码为 Output.Value
这些程序只演示模拟数据查询和结果交付。它们没有连接经纪商,也没有外部交易或绩效实验;交易控制流请看交易演示。测试层面的普通/PLM 对照见 CLI 示例的测试。