为什么Node.js子进程调用Python脚本时会出现跳过执行的问题?
问题原因
你遇到的问题核心是Python模块搜索路径不匹配,同时你没有捕获Python进程的错误输出,所以看不到导入失败的报错,误以为脚本被跳过了。
第一步:先捕获Python错误输出排查具体问题
你当前只监听了stdout,Python的导入错误会输出到stderr,所以你看不到报错,先给Node代码加上stderr监听:
const python = spawn('python', [path.join(settings.PROJECT_DIR, '/tests_explorer/scripts/product/product.py').replace(/\\/g, "/"), 'node.js', 'python']); python.stdout.on('data', function (data) { console.log('Pipe data from python script ...'); dataToSend = data.toString(); console.log(dataToSend) }); // 新增错误输出监听 python.stderr.on('data', function (data) { console.error('Python error output:'); console.error(data.toString()); });
加完之后就能看到Python的具体报错,大概率是ModuleNotFoundError: No module named 'general'。
第二步:解决模块导入路径问题
Python导入模块时只会从sys.path列表里的路径搜索,你直接在脚本所在目录执行Python时,当前目录会自动加入sys.path,但通过Node的spawn调用时,默认工作目录是Node进程的运行目录,不是Python脚本所在目录,所以找不到你自定义的general模块,可任选以下一种方法解决:
- 方法1:在Python脚本开头添加脚本所在目录到搜索路径
修改你的product.py开头代码:
import sys import os # 把当前脚本所在目录加入模块搜索路径 sys.path.append(os.path.dirname(os.path.abspath(__file__))) import general.general # 注意Python注释用#,不要用//,否则会报语法错误 print('#Hello from python#') print('First param:'+sys.argv[1]+'#') print('Second param:'+sys.argv[2]+'#') name = general.id_generator(9) print(name)
这个方法兼容性最好,不管从哪个目录调用脚本都能正常导入模块。
- 方法2:指定spawn调用时的工作目录为Python脚本所在目录
修改Node的spawn代码,添加cwd参数:
const pyScriptPath = path.join(settings.PROJECT_DIR, '/tests_explorer/scripts/product/product.py').replace(/\\/g, "/") const pyScriptDir = path.dirname(pyScriptPath) const python = spawn('python', [pyScriptPath, 'node.js', 'python'], { cwd: pyScriptDir // 指定工作目录为脚本所在目录 });
- 方法3:添加general模块所在路径到PYTHONPATH环境变量
你也可以在调用spawn时传入环境变量,把general模块的父目录加到PYTHONPATH中,适合多个脚本共用自定义模块的场景。
额外注意
你Python代码里的//my own utils是非法注释,Python的单行注释用#,如果实际代码里也是写的//要改成#,否则会直接报语法错误。
内容的提问来源于stack exchange,提问作者Josh Parinussa
相关产品推荐
相关产品推荐

