Is there a way to run Python from within Mathematica?

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 Prints 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[];

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"]
    ]
]

enter image description here

I had to use anaconda's python executable - Mathematica was crashing the system's python runtime.


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:

enter image description here

The output of these cells is a Wolfram Language expression that you can then compute with.