如何从Python调用Matlab函数、传参、获取返回值并避免重复启动
现有代码问题说明
- 传参逻辑错误:Matlab命令行下
函数名 参数的简写调用形式,会把空格后内容识别为字面字符串,不会解析为变量,因此实际传入的是硬编码的'my_name',而非Python变量存储的john wayne。 - 返回值传递链路缺失:subprocess默认仅能获取进程退出码,未对Matlab内部变量做序列化传输,Python侧无法拿到函数执行后的返回值。
- 调用模式低效:每次调用都启动全新Matlab进程,冷启动加载运行环境的开销通常在数秒到十几秒,频繁调用性能极差。
- Matlab函数语法错误:
return printed_line不符合Matlab语法规范,Matlab的return关键字仅用于提前跳出函数,不需要携带返回值,返回值通过函数头定义的输出变量赋值即可传递。
修正后的Matlab函数(hello_world.m)
function [printed_line] = hello_world(name) str_to_display = strcat('Hello World from: ', string(name)); disp(str_to_display); printed_line = strlength(name); end
落地方案
推荐方案:使用Matlab官方Python引擎(满足全部3项需求)
该方案仅需启动一次Matlab进程常驻后台,后续所有函数调用都复用该进程,完全消除重复冷启动开销;参数支持直接传入Python原生数据类型,返回值可直接被Python识别,不需要手动做字符串解析,适配后续复杂Matlab函数调用场景。
配置步骤
- 找到本地Matlab安装目录下的
extern/engines/python路径,在该路径下执行python setup.py install完成引擎安装,注意Python版本需与当前Matlab支持的版本匹配。
注意:如果需要传递数组、矩阵、结构体等复杂类型参数,Matlab引擎会自动完成Python和Matlab之间的类型转换,不需要手动做格式拼接,稳定性远高于subprocess拼命令的方案。
调用示例代码
import matlab.engine # 仅第一次调用时启动Matlab引擎,启动耗时约数秒,后续全程复用 eng = matlab.engine.start_matlab() # 如果hello_world.m不在Python当前工作目录,执行下行添加m文件路径 # eng.addpath('你的hello_world.m存放的绝对路径', nargout=0) my_name = 'john wayne' # nargout参数指定当前调用的Matlab函数返回值个数,这里我们有1个返回值 printed_line = eng.hello_world(my_name, nargout=1) # 验证输出 print(f"Matlab函数返回值:{printed_line}") # 后续调用其他复杂Matlab函数直接用eng.函数名(参数, nargout=返回值个数)格式即可 # 所有调用完成后需要关闭引擎时执行eng.quit()
临时测试方案:subprocess调用(仅满足前2项需求,无法解决冷启动问题)
如果暂时不想安装Matlab引擎,可以通过参数拼接修正传参问题,同时让Matlab把返回值序列化为JSON格式输出到标准输出,Python侧解析拿到结果。该方案每次调用都会重启Matlab,冷启动开销大,仅适合临时测试使用。
调用示例代码
import subprocess import json my_name = 'john wayne' # 拼接Python变量值到Matlab执行命令,字符串参数用Matlab要求的单引号包裹 # 让Matlab将执行状态和返回值封装为JSON打印,方便Python解析 run_matlab = f'''matlab -nodisplay -nojvm -nosplash -nodesktop -r " try res = hello_world('{my_name}'); disp(jsonencode(struct('code',0,'data',res))); exit(0); catch e disp(jsonencode(struct('code',1,'msg',getReport(e)))); exit(1); end "''' # 捕获Matlab进程的标准输出 proc = subprocess.run(run_matlab, shell=True, capture_output=True, text=True) # 遍历输出行,解析JSON结果,普通打印内容直接输出 for line in proc.stdout.strip().split('\n'): try: result = json.loads(line) if result['code'] == 0: printed_line = result['data'] print(f"Python侧获取到返回值:{printed_line}") else: print(f"Matlab执行报错:{result['msg']}") except json.JSONDecodeError: print(line)
内容的提问来源于stack exchange,提问作者Alessandro
相关产品推荐
相关产品推荐

