PyCall.jl
Package to call Python functions from the Julia language
Install / Use
/learn @JuliaPy/PyCall.jlREADME
Calling Python functions from the Julia language
This package provides the ability to directly call and fully interoperate with Python from the Julia language. You can import arbitrary Python modules from Julia, call Python functions (with automatic conversion of types between Julia and Python), define Python classes from Julia methods, and share large data structures between Julia and Python without copying them.
Installation
Within Julia, just use the package manager to run Pkg.add("PyCall") to
install the files. Julia 0.7 or later is required.
The latest development version of PyCall is available from https://github.com/JuliaPy/PyCall.jl. If you want to switch to this after installing the package, run:
Pkg.add(PackageSpec(name="PyCall", rev="master"))
Pkg.build("PyCall")
By default on Mac and Windows systems, Pkg.add("PyCall")
or Pkg.build("PyCall") will use the
Conda.jl package to install a
minimal Python distribution (via
Miniconda)
that is private to Julia (not in your PATH). You can use the Conda Julia
package to install more Python packages, and import Conda to print
the Conda.PYTHONDIR directory where python was installed.
On GNU/Linux systems, PyCall will default to using
the python3 program (if any, otherwise python) in your PATH.
The advantage of a Conda-based configuration is particularly
compelling if you are installing PyCall in order to use packages like
PyPlot.jl or
SymPy.jl, as these can then
automatically install their Python dependencies. (To exploit this in
your own packages, use the pyimport_conda function described below.)
Specifying the Python version
If you want to use a different version of Python than the default, you
can change the Python version by setting the PYTHON environment variable
to the path of the python (or python3 etc.) executable and then re-running Pkg.build("PyCall").
In Julia:
ENV["PYTHON"] = "... path of the python executable ..."
# ENV["PYTHON"] = raw"C:\Python310-x64\python.exe" # example for Windows, "raw" to not have to escape: "C:\\Python310-x64\\python.exe"
# ENV["PYTHON"] = "/usr/bin/python3.10" # example for *nix
Pkg.build("PyCall")
Note also that you will need to re-run Pkg.build("PyCall") if your
python program changes significantly (e.g. you switch to a new
Python distro, or you switch from Python 2 to Python 3).
To force Julia to use its own Python distribution, via Conda, simply
set ENV["PYTHON"] to the empty string "" and re-run Pkg.build("PyCall").
The current Python version being used is stored in the pyversion
global variable of the PyCall module. You can also look at
PyCall.libpython to find the name of the Python library or
PyCall.pyprogramname for the python program name. If it is
using the Conda Python, PyCall.conda will be true.
(Technically, PyCall does not use the python program per se: it links
directly to the libpython library. But it finds the location of
libpython by running python during Pkg.build.)
Subsequent builds of PyCall (e.g. when you update the package via
Pkg.update) will use the same Python executable name by default,
unless you set the PYTHON environment variable or delete the file
Pkg.dir("PyCall","deps","PYTHON").
Note: If you use Python
virtualenvs,
then be aware that PyCall uses the virtualenv it was built with by
default, even if you switch virtualenvs. If you want to switch PyCall
to use a different virtualenv, then you should switch virtualenvs and
run rm(Pkg.dir("PyCall","deps","PYTHON")); Pkg.build("PyCall").
Alternatively, see Python virtual environments
section below for switching virtual environment at run-time.
Note: Usually, the necessary libraries are installed along with
Python, but pyenv on MacOS
requires you to install it with env PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.4.3. The Enthought Canopy Python distribution is
currently not supported.
As a general rule, we tend to recommend the Anaconda Python
distribution on MacOS and
Windows, or using the Julia Conda package, in order to minimize headaches.
Usage
Here is a simple example to call Python's math.sin function:
using PyCall
math = pyimport("math")
math.sin(math.pi / 4) # returns ≈ 1/√2 = 0.70710678...
Type conversions are automatically performed for numeric, boolean, string, IO stream, date/period, and function types, along with tuples, arrays/lists, and dictionaries of these types. (Python functions can be converted/passed to Julia functions and vice versa!) Other types are supported via the generic PyObject type, below.
Multidimensional arrays exploit the NumPy array interface for
conversions between Python and Julia. By default, they are passed
from Julia to Python without making a copy, but from Python to Julia a
copy is made; no-copy conversion of Python to Julia arrays can be achieved
with the PyArray type below.
Keyword arguments can also be passed. For example, matplotlib's pyplot uses keyword arguments to specify plot options, and this functionality is accessed from Julia by:
plt = pyimport("matplotlib.pyplot")
x = range(0;stop=2*pi,length=1000); y = sin.(3*x + 4*cos.(2*x));
plt.plot(x, y, color="red", linewidth=2.0, linestyle="--")
plt.show()
However, for better integration with Julia graphics backends and to
avoid the need for the show function, we recommend using matplotlib
via the Julia PyPlot module.
Arbitrary Julia functions can be passed to Python routines taking function arguments. For example, to find the root of cos(x) - x, we could call the Newton solver in scipy.optimize via:
so = pyimport("scipy.optimize")
so.newton(x -> cos(x) - x, 1)
A macro exists for mimicking Python's "with statement". For example:
@pywith pybuiltin("open")("file.txt","w") as f begin
f.write("hello")
end
The type of f can be specified with f::T (for example, to override automatic
conversion, use f::PyObject). Similarly, if the context manager returns a type
which is automatically converted to a Julia type, you will have override this
via @pywith EXPR::PyObject ....
If you are already familiar with Python, it perhaps is easier to use
py"..." and py"""...""" which are equivalent to Python's
eval and
exec,
respectively:
py"""
import numpy as np
def sinpi(x):
return np.sin(np.pi * x)
"""
py"sinpi"(1)
You can also execute a whole script "foo.py" via @pyinclude("foo.py") as if you had pasted it into a py"""...""" string.
When creating a Julia module, it is a useful pattern to define Python
functions or classes in Julia's __init__ and then use it in Julia
function with py"...".
module MyModule
using PyCall
function __init__()
py"""
import numpy as np
def one(x):
return np.sin(x) ** 2 + np.cos(x) ** 2
"""
end
two(x) = py"one"(x) + py"one"(x)
end
Note that Python code in py"..." of above example is evaluated in a
Python namespace dedicated to MyModule. Thus, Python function one
cannot be accessed outside MyModule.
Troubleshooting
Here are solutions to some common problems:
- By default, PyCall doesn't include the current directory in the Python search path. If you want to do that (in order to load a Python module from the current directory), just run
pushfirst!(pyimport("sys")."path", "").
Python object interfaces
PyCall provides many routines for
manipulating Python objects in Julia via a type PyObject described
below. These can be used to have greater control over the types and
data passed between Julia and Python, as well as to access additional
Python functionality (especially in conjunction with the low-level interfaces
described later).
Types
PyObject
The PyCall module also provides a new type PyObject (a wrapper around
PyObject* in Python's C API) representing a reference to a Python object.
Constructors PyObject(o) are provided for a number of Julia types,
and PyCall also supplies convert(T, o::PyObject) to convert
PyObjects back into Julia types T. Currently, the types supported
are numbers (integer, real, and complex), booleans, strings, IO streams,
dates/periods, and functions, along with tuples and arrays/lists
thereof, but more are planned. (Julia symbols are converted to Python
strings.)
Given o::PyObject, o.attribute in Julia is equivalent to o.attribute
in Python, with automatic type conversion. To get an attribute as a
PyObject without type conversion, do o."attribute" instead.
The `keys(o
Related Skills
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
claude-opus-4-5-migration
83.9kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
model-usage
339.3kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
