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.