Python 程序
除了用节点画布编写的图形程序(Graph),程序还可以直接调用 Python 脚本(Python)。把程序类型设为 Python、指定脚本文件与入口函数后,程序运行时就会调用该函数,从而在图形程序中复用已有的 Python 代码。
INFO
Python 程序在运行时被当作自包含的单个 .py 文件加载,因此存在一些限制,详见脚本的执行方式。
用途
- 实现复杂的计算与逻辑:在画布中完成复杂计算往往需要连接大量节点,把这些计算交给 Python 可以避开繁琐的连线,也便于复用已有的 Python 代码与第三方库;
- 扩展软件功能:Python 程序可以像内置节点一样被图形程序调用(见在图形程序中调用 Python 程序),因此可以用它实现基于 Python 的自定义节点,补充内置节点没有的能力。
新建 Python 程序
- 点击程序列表面板的 + 按钮,打开“新建程序”对话框。
- 在“类型”中选择
Python,填写名称与描述后点击“确认”。 - 在 Python 面板中填写:
- 函数名:脚本中被调用的函数名(不含括号),例如
run; - 脚本路径:
.py文件的位置。点击搜索按钮可以浏览选择,也可以把.py文件直接拖到面板上。
- 函数名:脚本中被调用的函数名(不含括号),例如
- 在选项面板中添加输入选项和输出选项,它们决定函数接收的参数与返回的值,详见调用约定。
函数名右侧是运行(F5)按钮,脚本路径右侧是选择、编辑、刷新和定位按钮;脚本内容以只读方式显示在面板下方,点击“刷新”可重新载入脚本内容,点击“编辑”会使用系统默认的编辑器打开脚本。
如果脚本位于程序的目录中,则会以程序相对路径保存,程序导出/导入时会一并迁移。
调用约定
参数
函数按输入选项的先后顺序接收位置参数:
| 选项类型 | 传入的 Python 值 |
|---|---|
整数 | int |
浮点数 | float |
布尔 | bool |
字符串 | str |
其余类型(JSON、向量、图像等)目前不能作为 Python 程序的输入。
返回值
函数返回的值按输出选项的先后顺序写入输出选项:
| 函数的返回 | 对应关系 |
|---|---|
None(或不返回值) | 程序不能有输出选项 |
| 单个值 | 程序只能有一个输出选项 |
| 元组 | 按顺序对应各个输出选项 |
返回值的个数必须与输出选项的个数一致,否则运行时会报错。返回值同样只支持 int、float、bool、str 四种类型。
示例
程序有一个输入选项(整数 秒)和两个输出选项(字符串 文本、整数 长度):
python
def run(seconds):
text = f"waited {seconds}s"
return text, len(text)函数也可以是 async def,此时会等待协程执行完毕:
python
import asyncio
async def run(seconds):
await asyncio.sleep(seconds)
text = f"waited {seconds}s"
return text, len(text)脚本的执行方式
脚本被当作自包含的单个 .py 文件加载,因此:
- 不支持相对导入:
from . import xxx会报attempted relative import with no known parent package; - 不能导入同目录中的其它模块:脚本所在目录不会加入
sys.path,import xxx找不到同目录的.py文件;标准库与已安装的第三方库的绝对导入不受影响; - 脚本不以
__main__模块执行,if __name__ == "__main__":中的代码不会运行; __file__是脚本的绝对路径,可以用Path(__file__).parent读取脚本同目录下的数据文件;- 脚本的标准输出与标准错误(即
print()的输出、写入sys.stderr的内容)不会出现在运行日志面板中,而是写入软件的后台日志文件:标准输出记为信息级,标准错误记为错误级。日志面板与运行实例绑定,而所有运行实例共用一个 Python 解释器,无法判断输出来自哪个运行实例,因此脚本的输出统一记入后台日志; - 脚本默认按 UTF-8 解码,也可以用文件头的编码声明(PEP 263)指定其它编码;
- 不会生成
__pycache__,项目目录中不会写入.pyc文件。
加载与缓存
- 每次运行程序都会重新读取脚本文件,因此修改脚本后无需重启软件,再次运行即可生效;
- 同一次运行中,同一个脚本只会加载一次:模块级变量在本次运行内一直存在,多次调用会沿用上一次的模块状态;不同的运行(包括不同的执行器)之间互不影响。
在图形程序中调用 Python 程序
与图形程序一样,Python 程序可以通过“调用程序”节点调用:节点上的输入连接器来自被调用程序的输入选项,输出连接器来自输出选项。因此常见的做法是把 Python 脚本包装成 Python 程序,再在图形程序中按需调用。
限制
- Python 面板不提供“停止”按钮:无法中断正在执行的 Python 函数,如果脚本中存在长时间不返回的循环或阻塞调用,需要等这次调用结束;
- 脚本只能是一个文件,不能按包的形式拆分为多个文件(见脚本的执行方式)。