将问题块中的代码抽象为模块

Abstracting code from question blocks to modules

我有一个工作面试(耶!),我正在努力重构它。我正在尝试找出将我的 code 块移动到 .py 文件中的好方法。特别是,我担心维护 docassemble 所做的一些奇特的事情(例如,我正在考虑的特定 code 块被标记为 initial: True)。

是否可以将 code 块正在执行的任何操作转换为函数,然后以使用这些函数的方式分配 docassemble 正在寻找的变量?大概这些函数的结果还需要在code块中处理?

下面是大致正确的方法吗(下面的代码)?我假设:

  1. 尝试 运行 Bcode.func(A ...) 如下,如果 A 未定义,将触发必要的异常导致 docassemble 搜索设置 A?
  2. 变量可以如下所示传递。
  3. returning 函数的工作原理如下。

所有这些假设是否正确/不正确?

所以...

如果这是我的 questions.yml 文件:

---
question: A?
yesno: A
---
# code setting value of B
---
code: |
    if A:
         answer = "A"
    elif B:
         answer = "B"
    else:
         answer = "C"
---

为了抽象出代码,我想我可能会做这样的事情?

questions.yml:

---
imports:
    - Bcode
---
question: A?
yesno: A
---
initial: True
code: |
    answer = Bcode.func(A, *args_to_set_value_of_B)
---

Bcode.py:

---
def func(a, *args_to_set_value_of_b):

    # code computing value of b

    if a:
        return "A"
    elif b:
        return "B"
    else:
        return "C"
---

如果你这样做

modules:
  - .Bcode

然后 docassemble 将 运行(实际上):

exec("from docassemble.yourpackage.Bcode import *", user_dict)

其中 user_dict 是面试答案(YAML 文件中 Python 代码的命名空间)。这将使名称 func 在您的采访的命名空间中可用,以便它可以在 code 块、Mako 模板等中使用。

您的 initial 块将引发异常,因为 Bcode 不是面试答案中的名字。

只要 a 为真,您的函数 func() 将始终引发异常,因为 b 未在 func().

的命名空间中定义

Docassemble 的工作原理是捕获 NameErrorIndexErrorAttributeError 异常,然后查找将定义任何变量的 questioncode 块未定义。 NameError 异常适用于任何类型的变量,但 IndexErrorAttributeError 异常仅适用于 DAObject 或其子类的实例。

当您将代码移动到模块文件中时,确保模块文件中的代码不会引发 NameError 异常非常重要,因为这些会导致混淆; docassemble 将尝试在面试答案命名空间中定义变量,但这永远不会解决模块内部的问题,因为无论如何该名称在模块内部都是未定义的。但是,模块文件中的代码在已从采访命名空间传递到模块命名空间的 DAObject 变量上引发 IndexErrorAttributeError 错误是安全的,因为当 docassemble 定义这些面试答案命名空间中的变量,定义也将在模块内可用。

我会避免将代码移动到没有明确接口的模块中。在 YAML 中包含包含采访逻辑的代码块是完全合适的。我保留可重用的抽象代码模块。