从MATLAB调用Python函数

77

我需要从MATLAB调用一个Python函数,我该怎么做?


2
MATLAB是否支持套接字? - Geo
1
显然它确实具有套接字支持http://code.google.com/p/msocket/,如果这有帮助。 - Adrian
1
如果我们要添加选项:https://github.com/kw/pymex - robince
与将Matlab代码转换为Python(还提到了一些调用接口)相关的内容,请参考以下链接:https://dev59.com/Vmkw5IYBdhLWcg3wg6yg - 0 _
为什么不接受答案?当问题被提出时,“正确”的答案并不存在,但现在已经有了:https://dev59.com/HHI-5IYBdhLWcg3wu7BU#29189167 - 0 _
https://mathworks.com/help/matlab/call-python-libraries.html - Priyanka
13个回答

47

我在我的系统上有一个类似的要求,这是我的解决方案:

在MATLAB中有一个叫做perl.m的函数,它允许你从MATLAB中调用perl脚本。根据你所使用的版本,它可能会被放置在某个位置。

C:\Program Files\MATLAB\R2008a\toolbox\matlab\general\perl.m

创建一个名为python.m的副本,快速查找并替换perl为python,仔细检查设置的命令路径是否指向您安装的python。现在,您应该能够从MATLAB运行python脚本。

示例

在python中保存为"sqd.py"的简单平方函数,如果我正式做这个,我会添加一些检查来测试输入参数、有效数字等。

import sys

def squared(x):
    y = x * x
    return y

if __name__ == '__main__':
    x = float(sys.argv[1])
    sys.stdout.write(str(squared(x)))

然后在MATLAB中

>> r=python('sqd.py','3.5')
r =
12.25
>> r=python('sqd.py','5')
r =
25.0
>>

2
"perl"只是执行Perl脚本的系统调用 - 除了“尝试Perl调用结果和其退出状态的结果”之外,Perl脚本与MATLAB之间没有数据传输。- http://www.mathworks.com/access/helpdesk/help/techdoc/ref/perl.html - Jacob
我同意它只是进行了一个系统调用,但如果不需要的话,为什么要用mex函数和套接字使事情变得复杂呢?在简单的层面上,对Python的调用确实有一个简单的数据传输。我会用一个例子来更新答案。 - Adrian
6
MATLAB的示例代码看起来很不错,你能否张贴(代码/链接)“python.m”?返回的数据有哪些限制 - 只有标量吗? - Jacob
我们可以将数组作为参数传递给Python文件吗? - Donbeo
请注意,这个方法可以工作,但它是一种hack方式,有很多路径实际上并没有任何意义,例如fullfile(matlabroot, 'sys\python\win32\bin\');指向的路径实际上并不存在,因为没有定义任何Python错误消息,所以在CTRL+F'd Perl.m中使用message('MATLAB:python:<>')错误消息是无效的。 - jrh
这个答案已经过时了。正如在下面指出的那样,自Matlab 2014b以来,您可以通过在Python调用前加上“py.”来直接使用(一些)Python功能。 - Giorgio Balestrieri

30

使用Matlab 2014b版本,可以直接从Matlab中调用Python库 。所有数据包名称前缀都会添加py.

>> wrapped = py.textwrap.wrap("example")

wrapped = 

  Python list with no properties.

    ['example']

5
这确实是一个很棒的功能,但似乎不完整——例如我不能用sklearn这种方式。有关详细信息,请参见我的问题 - Bastian Ebeling
py 前缀也可以用于用户定义的 Python 模块(脚本):例如 names = py.mymod.search(N)。正确的文档页面是:https://uk.mathworks.com/help/matlab/matlab_external/call-user-defined-custom-module.html。 - Kouichi C. Nakamura

20

尝试使用这个MEX文件来实际从MATLAB调用Python,而不是像其他人建议的反过来。它提供了相当不错的集成:http://algoholic.eu/matpy/

您可以轻松地执行以下操作:

[X,Y]=meshgrid(-10:0.1:10,-10:0.1:10);
Z=sin(X)+cos(Y);
py_export('X','Y','Z')
stmt = sprintf(['import matplotlib\n' ...
'matplotlib.use(''Qt4Agg'')\n' ...
'import matplotlib.pyplot as plt\n' ...
'from mpl_toolkits.mplot3d import axes3d\n' ...
'f=plt.figure()\n' ...
'ax=f.gca(projection=''3d'')\n' ...
'cset=ax.plot_surface(X,Y,Z)\n' ...
'ax.clabel(cset,fontsize=9,inline=1)\n' ...
'plt.show()']);
py('eval', stmt);

1
+1 感谢您提供的出色解决方案。请考虑将项目托管在GitHub上,以便其他人也可以找到它。 - Amro
2
对于那些感兴趣的人,我刚刚发现了另外两个类似的项目:pythoncallpymex(我自己还没有尝试过)。 - Amro

14
你可以将Python脚本嵌入到C程序中,然后再使用MEX将C程序与MATLAB配合使用,但与将结果转储到文件相比,这可能需要更多的工作。
你可以使用PyMat在Python中调用MATLAB函数。此外,SciPy还有几个MATLAB重复函数。
但是,如果你需要从MATLAB运行Python脚本,可以尝试使用system命令来运行脚本并将结果存储在文件中,然后在MATLAB中读取该文件。

11

正如 @dgorissen 所说,Jython 是最简单的解决方案。

只需从主页安装 Jython。

然后:

javaaddpath('/path-to-your-jython-installation/jython.jar')

import org.python.util.PythonInterpreter;

python = PythonInterpreter; %# takes a long time to load!
python.exec('import some_module');
python.exec('result = some_module.run_something()');
result = python.get('result');

请参阅文档以获取一些示例。

请注意:我从未真正使用过Jython,而且似乎从CPython中所知道的标准库没有完全实现在Jython中!

我测试过的小例子都能够正常运行,但是你可能需要将Python代码目录添加到sys.path之前。


2
很明显,集成起来会更容易。可惜的是,目前为止,你不能在Jython中使用像Numpy/Scipy/matplotlib这样的模块(因为C扩展)。当涉及到科学计算时,这些库确实是Python的强项。 - Amro
回答这个问题很困难。有人可以只需打开Python(而不是Matlab),并在REPL shell中进行读写操作。我猜只有使用Jython才能实现无缝集成。然而,如果使用ctypes,将Octave(而不是Matlab)与CPython进行集成可能会比较容易。 - Kijewski
(虽然Octave是Matlab的微不足道的替代品。) - Kijewski
CPython 允许将其解释器嵌入到 C 程序中(这就是 @algoholic 使用 MEX-files 所做的)。大部分代码用于在 Python 类型(numpy.ndarray 被用作 MATLAB N-D 矩阵的等效物)和 MATLAB 类型之间来回转换(实际上,在 MEX 中,使用的是 mxArray)。 - Amro
1
整个过程与您上面展示的类似,只是使用Python的C API而不是Jython Java API来评估解释器中的任意表达式...此外,您可以导入任何已安装的Python模块,包括整个“PyLab”集合。 - Amro

10

最简单的方法是使用MATLABsystem函数。

因此,基本上你可以像在命令提示符(Windows)或Shell(Linux)中执行一样,在MATLAB上执行Python函数:

system('python pythonfile.py')

以上代码适用于简单地运行一个 Python 文件。如果您想要运行一个 Python 函数(并给它一些参数),那么您需要类似下面这样的代码:

system('python pythonfile.py argument')

举个具体的例子,可以参考Adrian在这个问题的回答中提供的Python代码,并将其保存到一个Python文件中,例如test.py。然后将该文件放置在MATLAB目录中,并在MATLAB上运行以下命令:

system('python test.py 2')

你将获得输出为4或2^2。

注意:MATLAB在当前目录中查找使用system命令指定的Python文件。

这可能是解决你的问题最简单的方法,因为你只需在MATLAB中使用现有函数即可完成你的任务。


这就是我一直在做的事情,但我遇到了一个神秘的问题——我的Python脚本的参数之一是一个文件。当从MATLAB调用时,Python脚本找不到该文件(尽管所有脚本都与文件在同一个目录中,并且在MATLAB脚本中指定了完整路径)。非常令人恼火。 - whlteXbread
这些建议看起来很不错,但我收到了错误信息:“'python' 不是内部或外部命令,也不是可运行的程序或批处理文件。” - NeStack

7

从Matlab 2014b开始,可以直接调用Python函数。 使用前缀py,然后是模块名称,最后是函数名称,如下所示:

result = py.module_name.function_name(parameter1);

如果你在与Python脚本不同的工作目录中,从Matlab调用Python脚本时,请确保将脚本添加到Python搜索路径中。

更多详细信息请参见此处


4
我已经将perl.m适配成python.m,并附上参考资料供其他人使用,但我似乎无法从Python脚本中获取任何输出并返回给MATLAB变量 :(

这是我的M文件;请注意,我在代码中直接指向Python文件夹C:\python27_64,这在您的系统中可能会有所不同。
function [result status] = python(varargin)
cmdString = '';
for i = 1:nargin
    thisArg = varargin{i};
    if isempty(thisArg) || ~ischar(thisArg)
        error('MATLAB:python:InputsMustBeStrings', 'All input arguments must be valid strings.');
    end
    if i==1
        if exist(thisArg, 'file')==2
            if isempty(dir(thisArg))
                thisArg = which(thisArg);
            end
        else
            error('MATLAB:python:FileNotFound', 'Unable to find Python file: %s', thisArg);
        end
    end
  if any(thisArg == ' ')
    thisArg = ['"', thisArg, '"'];
  end
  cmdString = [cmdString, ' ', thisArg];
end
errTxtNoPython = 'Unable to find Python executable.';
if isempty(cmdString)
  error('MATLAB:python:NoPythonCommand', 'No python command specified');
elseif ispc
  pythonCmd = 'C:\python27_64';
  cmdString = ['python' cmdString];  
  pythonCmd = ['set PATH=',pythonCmd, ';%PATH%&' cmdString];
  [status, result] = dos(pythonCmd)
else
  [status ignore] = unix('which python'); %#ok
  if (status == 0)
    cmdString = ['python', cmdString];
    [status, result] = unix(cmdString);
  else
    error('MATLAB:python:NoExecutable', errTxtNoPython);
  end
end
if nargout < 2 && status~=0
  error('MATLAB:python:ExecutionError', ...
        'System error: %sCommand executed: %s', result, cmdString);
end

编辑:

解决了我的问题:原始的perl.m指向MATLAB文件夹中的Perl安装程序,通过更新PATH并调用Perl来解决。上面的函数指向我的Python安装程序。当我调用我的function.py文件时,它在不同的目录中,并调用该目录中的其他文件。这些文件没有反映在PATH中,因此我必须将我的Python文件easy_install到我的Python发行版中。


4

关于MATLABsystem()函数,有一个鲜为人知(且很少有记录)的事实:在类Unix系统上,它会使用在启动MATLAB时给定的环境变量SHELLMATLAB_SHELL中指定的解释器。因此,如果您使用以下命令启动MATLAB:

SHELL='/usr/bin/python' matlab

任何后续的system()调用将使用Python作为解释器,而不是您的默认shell。

在Windows上对我没用。(我按照通常的方式创建了环境变量) - Amro
嗯,我想你在Matlab内部检查了变量是否真的设置了吧?但是如果Matlab在Windows上有不同的标准来决定使用哪个shell,我也不会感到太惊讶。 - quazgar
是的,我在MATLAB中检查了getenv('SHELL')。无论如何,你应该提到这个技巧不幸只适用于Linux/Mac。 - Amro
1
+1 这里似乎提到了 SHELL 变量:http://www.mathworks.com/help/matlab/ref/matlabunix.html(相应的 Windows 页面则没有) - Amro

3

由于MATLAB与Java无缝集成,因此您可以使用Jython编写脚本并从MATLAB中调用它(您可能需要添加一个纯JKava包装器来实际调用Jython代码)。我从未尝试过,但我认为应该可以。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接