I know there is some support for running Mathematica from Python, but is there any way to do the reverse. For example, to import some Python classes and use them in Mathematica?
-
$\begingroup$ related: mathematica.stackexchange.com/q/1894/5 (I don't know enough to tell if it's a dupe or not) $\endgroup$– rm -rf ♦Dec 3, 2012 at 21:59
-
$\begingroup$ @rm-rf: Different: that relies on .NET. $\endgroup$– oromeDec 3, 2012 at 22:01
-
2$\begingroup$ Google Pythonika $\endgroup$– Mark McClureDec 3, 2012 at 22:19
-
3$\begingroup$ @Jens He says he wants "to import some Python classes and use them in Mathematica". That's exactly what Pythonika does. I've used it to run sage from Mathematica. One of the dumbest things I've ever done, but I did it: facstaff.unca.edu/mcmcclur/Mathematica/Sage $\endgroup$– Mark McClureDec 3, 2012 at 22:40
-
2$\begingroup$ @MarkMcClure: Pythonica seems not to be a viable solution. I can't get it to load (0S X 10.8.2, Python 2.7.2, Mathematica 9.0). Are there any alternatives? $\endgroup$– oromeDec 12, 2012 at 1:52
6 Answers
Building off of @M.R.'s idea, it is possible to set up an interactive python shell using StartProcess
as opposed to RunProcess
, allowing for much more flexible connectivity between Python and Wolfram without as much overhead. In it's simplest form, one can open a connection, interact with it, and close it using the following example:
path = "e:\\Programs\\python27\\python"; (*insert OS-appropriate path \
to python*)
p = StartProcess[{path, "-i"}]; (*the'-i' argument is important*)
cmd = "print 'hello'"; (*or any valid python expression*)
Pause[1]; (* important!!! *)
WriteLine[p, cmd];
out = ReadString[p, EndOfBuffer]
KillProcess@p;
Pausing after the StartProcess
call is important in order to avoid the cmd
being sent to the python interpreter before it has finished loading. A much shorter pause can be used on faster computers.
I've put together a short package to streamline python interactivity. The version I've posted below also reads the python shell text (which is delivered on stderr) and prints that to the Message window if the FrontEnd
is active or simply Print
s it if the command line is being used. It works nicely with simple commands pcmd@"print 'hello'"
and I've had success with some sophisticated operations such as web scraping with Splinter and BeautifulSoup. It coughs when trying to use something like Tkinter, but it just doesn't work as opposed to throwing some form of error, making it a bit difficult to debug.
BeginPackage["wlPython`"];
$pythonprocess = Null;
$pythonpath = "e:\\Programs\\python27\\python";
$pythonpause = 0.250; (* Pause in seconds to receive error information *)
startPython::usage = "Starts the python process";
endPython::usage = "Ends the python process";
pcmd::usage = "issue a python command";
(* Check for FrontEnd and set as appropriate, can be overridden *)
$pyfrontend = $FrontEnd=!=Null;
Begin["`Private`"];
Clear[startPython]
startPython[path_:$pythonpath]:=Module[{err},
$pythonprocess = StartProcess[{path,"-i"}];
wlPython`pyerrcheck[];
$pythonprocess
]
Clear[endPython]
endPython[process_:Unevaluated@$pythonprocess]:=Module[{},
KillProcess@Evaluate@process;
NotebookWrite[MessagesNotebook[],
Cell[RawBoxes@ToBoxes["Python process ended",TraditionalForm],"Output"]];
]
Clear[pcmd]
pcmd[cmd_String,process_:Unevaluated@$pythonprocess]:=Module[{status,err,out,p},
p = Evaluate[process];
status = ProcessStatus[p];
If[status=="Running",
WriteLine[p,cmd];
wlPython`pyerrcheck[];
out = ReadString[p,EndOfBuffer]
];
out
]
Clear[pyerrcheck]
pyerrcheck[]:=Module[{err},
Pause@$pythonpause;
err = ReadString[ProcessConnection[$pythonprocess,"StandardError"],EndOfBuffer];
If[$pyfrontend,
NotebookWrite[MessagesNotebook[],
Cell[RawBoxes@ToBoxes[err,TraditionalForm],"Output"]];,
Print[err];
]
]
End[];
EndPackage[];
-
1$\begingroup$ This (excellent and previously accepted) answer is outdated as of 11.2. $\endgroup$– oromeMar 14, 2018 at 17:52
Here is a more robust solution using Process
:
Clear[runPython];
runPython::badCommand ="Python code failed to run with message `StandardError`";
$pyimports="from random import randint
";
runPython[str_String, imports_:$pyimports] := Module[
{pyscrpt = ToString[$pyimports<>str, CharacterEncoding->"ASCII"], file=CreateTemporary[], res},
Export[file,pyscrpt,"Text"];
res = RunProcess[{"/anaconda/bin/python",file}];
DeleteFile[file];
If[res["ExitCode"]!=0,
Return @ Failure["badCommand",<|"MessageTemplate" :> runPython::badCommand,"MessageParameters"-> <|"Message" -> res["StandardError"]|>|>],
Return @ ImportString @ res["StandardOutput"]
]
]
I had to use anaconda's python executable - Mathematica was crashing the system's python runtime.
-
$\begingroup$ " Here is a more robust solution using
Process
:" More robust than what? $\endgroup$ Nov 30, 2016 at 19:33 -
1
-
$\begingroup$ did you mean to write
(...) ToString[imports<>str (...)
in the second line of the definition of the function? The way it is now the second argument ofrunPython
is useless $\endgroup$– glSJan 14, 2017 at 21:06 -
$\begingroup$ This (excellent and previously accepted) answer is outdated as of 11.2. $\endgroup$– oromeMar 14, 2018 at 17:52
Since 11.2 Mathematica has supported ExternalEvaluate
and since 11.3 this functionality has been conveniently available simply by beginning an input cell with >
which produces an external code cell:
The output of these cells is a Wolfram Language expression that you can then compute with.
-
3$\begingroup$ Please clarify with an example, say, for Python, including when Python is not the default OS system installation but another, e.g., anaconda's. $\endgroup$– murrayMar 14, 2018 at 19:06
-
1
-
1$\begingroup$ No, but it certainly would be helpful. $\endgroup$ Feb 5, 2019 at 10:52
-
$\begingroup$ But it seems that Mathematica complains when you try to import some python packages? $\endgroup$– MKFMar 2, 2019 at 12:43
-
$\begingroup$ You may have to configure python by calling the
RegisterExternalEvaluators[]
function and supplying a path to your executable $\endgroup$ Apr 22, 2019 at 23:42
If all you want is to invoke Python scripts and use the output they generate in Mathematica, then simply
pythonOutput = Import["!python fullpathtoscript/your_scipt.py --some_opt arg arg ...", "String"];
is sufficient.
-
$\begingroup$ Commands like this don't work at all for me in Mathematica 10.0.1. $\endgroup$– MikeNov 21, 2014 at 3:44
-
-
$\begingroup$ @ThomasH: Can you give me a specific example of something that works that I can try. It doesn't even work for me anymore (10.0.2.0). $\endgroup$– oromeApr 6, 2015 at 20:24
-
$\begingroup$ For a MWE, I made a file in my home directory called test.py containing "print('hello world')", then in Mathematica (also pointed at my home directory by default), 'Import["!python test.py","String"]' produces the string "hello world". I have a simple but slightly more complicated example I can point you to on github if you'd like. $\endgroup$– ThomasHApr 9, 2015 at 17:14
Here is an approach that works on Mac OS X or unix-like systems without the need to explicitly create any temp directory:
code = "print \\\"hello, starting\\\"
for i in [1,2,3]:
\t print i*i
"
(* ==>
"print \\\"hello, starting\\\"
for i in [1,2,3]:
print i*i
"
*)
RunProcess[$SystemShell, "StandardOutput",
"printf \"" <> code <> "\" | python
exit
"]
(* ==>
"hello, starting
1
4
9
"
*)
First, I define the string containing the Python code. I included a test message to illustrate how you have to escape the quotation marks using \\\"
inside the string, because it's going to be passed into a printf
command on the shell command line. THat printf
is subsequently piped into python
. Note that I didn't have to specify the path because it's found from the SystemShell
environment.
The interaction with Mathematica takes place via RunProcess
, and the standard output of the Python script is directly captured into Mathematica. Again, it's not necessary to bother with any temporary files in this approach.
-
$\begingroup$ Can you contrast this with the
Import
approach? Is it just that it avoids using an existing script? FWIW, I'd never write the Python code in the Mathematica environment: the code editing tools are just too poor. $\endgroup$– oromeApr 5, 2015 at 14:14 -
$\begingroup$ Also, can you show how it would work with an existing script? $\endgroup$– oromeApr 5, 2015 at 14:21
-
$\begingroup$ @raxacoricofallapatorius Yes, my main point is to have the script and everything it needs completely inside Mathematica. If you already have an existing script outside Mathematica, then it's not a real two-way interaction, I'd say. But what to do with an existing script specifically would depend on the application. I can't think of anything general to say about that, except that it would be possible, e.g., to pass arguments to it using my approach. An important advantage of my approach is, however, that it makes the entire process portable: you can email the notebook without attachments. $\endgroup$– JensApr 5, 2015 at 16:13
-
$\begingroup$ Yes; also, it looks like the approach I had no longer works. $\endgroup$– oromeApr 5, 2015 at 18:19
-
2$\begingroup$ Oh well, that's just a formatting error when I manually tried to put the python string into a form that looks right in the code cell above. One extra space crept in, and that kills python. I fixed it. If it still doesn't work, it could be dependent on the OS and version of Mathematica. This
RunProcess
command doesn't work in earlier versions... by the way, another way of interacting with python is through the clipboard on Mac. But I don't know what your actual goal is, so I'll skip that for now. $\endgroup$– JensApr 5, 2015 at 21:19
There's a "Python link" called Pythonika. I have used it briefly and it works.
What it does:
- translates basic data types, including arbitrary size integers, to/from Python
- makes it possible to implement functions in Python and call them from Mathematica
It does not provide any means to work with classes directly. Also, the implementation is rather hackish using unsafe practices (e.g. symbols are not localized to a context, and this has bitten me). To implement a link properly it would take lot more work.
I made a few basic fixes (e.g. using contexts), but I haven't used the thing in a long time. Contact me if you want the fixes.
-
-
1$\begingroup$ Correct, it is deprecated and seems no longer maintained... $\endgroup$– M.R.Jan 26, 2015 at 2:36
-
$\begingroup$ Hi, @Szabolcs, is there librarylink way use of python in Mathematica? $\endgroup$ Sep 5, 2016 at 14:19
-
$\begingroup$ @matheorem There's no simple way. LibraryLink or MathLink won't solve the problem of transferring and converting data structures between Python and Mathematica. Someone would have to think about how that conversion should work and implement it on top of LibraryLink or MathLink. (Actually the right choice is MathLink here in my opinion.) That is a job that would take several weeks of full time work, even for a simple version. I don't know who has time for that. $\endgroup$– SzabolcsSep 5, 2016 at 14:22
-
1