Julia Calling Python Calling Julia...

Oct 6, 2013   #julialang  #projects  #code 

Julia is a young programming language. This means that its native libraries are immature. We are in a time when Julia is a mature enough as a language that it is out-pacing its libraries.

One way to use mature libraries from a young language is to borrow them from another language. In this case, we’ll be borrowing from Python. (Julia can also easily wrap libraries from C or Fortran. In fact, this capability was important in combination with Python’s great C-interface to make calling Python from Julia do-able.)

Python from Julia: PyCall.jl

Calling Python from Julia requires PyCall. You can get it using Pkg.add("PyCall").

Let’s start with a “Hello, World” scale example.

using PyCall
pyeval("2+2") #=> 4
pyeval("str(5)") #=> "5"

# doing things by hand, for fun :)
math = pyimport(:math) #=> PyObject <module 'math'>
pycall(math["sin"],Float64,1) #=> 0.8414709848078965

Using Python Libraries from Julia

For a quick practical example of Python libraries filling in Julia’s current gaps, we can use Python’s matplotlib for graphing. If you also install matplotlib, you can run this fun code snippet I found on the mailing list. If you run it, it will pop up a window with a graph of a nice dotted, squiggley, red line.

using PyCall
@pyimport pylab
x = linspace(0,2*pi,1000); y = sin(3*x + 4*cos(2*x));
pylab.plot(x, y; color="red", linewidth=2.0, linestyle="--")
pylab.show() 

pylab is the name for the Python module that includes matplotlib and numpy in a single namespace, according to matplotlib’s docs; it is the recommended interface to matplotlib. @pyimport is a Julia macro that is equivalent to a using statement on the Julia equivalent of the Python module. What this means is that we can now use pylab as if it’s a Julia module, which is what the dot-notation (pylab.plot) is taking advantage of. We use two functions from pylab: plot and show. Notice that we don’t have to do anything special when we invoke them: they look just like Julia functions, right down to the keyword arguments.

Julia from Python: the julia module

This is the less polished direction; it’s not really intended for public consumption yet. To get the Python module that you need to call Julia, git clone https://github.com/JuliaLang/IJulia.jl. Then, inside the IJulia.jl/python/ folder, run python setup.py install. (you may need sudo on that last command)

First, the opening incantation:

import julia
j = julia.Julia()

The second line will take a while to run; it’s starting and setting up Julia.

Now, you’ll be able to call Julia from the Python REPL. For example:

j.run("2+2") #=> 4
j.run("sin(pi)") #=> 1.2246467991473532e-16
j.run("x = 5") #=> 5
j.run("x += 2") #=> 7
j.run("x") #=> 7

Let’s be best friends: Mutual Recursion.

This section is a code example. We’ll start at the top, and then wander down through the implementation. You can find all the code on github.

If you clone that repo, you can open a Python REPL up inside that folder and run the following:

import pyiseven
pyiseven.even(5)

As one would hope, you’ll get False back. The import line probably took a really long time to load; the even function seems pretty straight forward given its name and behavior. But, let’s take a look at pyiseven.py anyway.

import julia
j = julia.Julia()

def even(x):
  j.run("using IsOdd")
  return not j.run("IsOdd.odd(" + str(x) + ")")

Oh no! This looks terribly inefficient: even if Julia is 20x faster than Python, calling another programming language to figure out if your number is odd is a bad plan.

Maybe we should take a look at IsOdd.jl:

module IsOdd

using PyCall
@pyimport pyiseven

function odd(x)
  if x == 1
    true
  elseif x == 0
    false
  else
    pyiseven.even(x-1)
  end
end

end

Oh no! It gets worse! We make another function call back into Python’s even function on every call to Julia’s odd. That means that it takes two function calls (and two trips between languages) for each increment of even's argument. (In fact, if you call pyiseven.even(201) (or greater), then the stack explodes, unfortunately.) If you find that your production code is too slow because you’re using mutual recursion between nine different languages, blame Dan Luu for this terrible idea.

tl;dr

You should really check out PyCall, which does a great job of translating between Python and Julia values and modules.

If you’ve been using IPython notebook, then you should also try IJulia notebook. (Same frontend, different language). You may have noticed that the IJulia project’s repo is the origin of that Python julia module.