Comparison to PyCall
The existing package PyCall is another similar interface to Python.
You can use both PythonCall and PyCall in the same session, provided they are both using the same Python library. One way to ensure this is to set JULIA_PYTHONCALL_EXE=PYCALL (see Environment variables).
Here is a comparison of the designs:
- Flexibility of conversion. The mechanisms for data conversion from Python to Julia are different. In
PyCall, conversion toT(viaconvert(T,::PyObject)) essentially only takesTinto account, so for example whenT=Realthen the input will always be converted to a Pythonfloat, which is then converted to aCdouble. InPythonCall, conversion takes into account both the target typeTand the Python type of the Python object, and an extensible system allows one to declare conversions for any combination. Many conversions for overlapping combinations can be defined and the most specific one takes precedence. Hence inPythonCall, converting to aRealmight return anInt(e.g. the input is aint), orCdouble(e.g. the input isfloat), orRational{BigInt}, or... - Lossiness of conversion from Python. In
PyCall, the defaultPyAnyconversion from Python to Julia can be lossy in the sense that it is impossible to recover the original value exactly. For example a list of ints is converted to aVector{Int}which is a copy of the data, and therefore modifying the original list is not possible. It is also a source of off-by-one errors, sinceVectorandlisthave different indexing semantics. InPythonCall, the default conversion is toPyObject(non-lossy), and even if you convert toAnythen by default this will be non-lossy: for example alistwill be converted to aPyListwhich is aVector-like view of the list. - Lossiness of conversion to Python. Similarly, in
PyCallthe default conversion from Julia to Python can be lossy: aVector{Int}will be converted to alistofints for example, losing mutability of the original vector. InPythonCall, only immutable values are truly converted to Python, everything else is wrapped into a Python wrapper around the Julia value: aVector{Int}is wrapped into ajuliacall.VectorValuewhich is alist-like sequence type - Automatic conversion. In
PyCall, most function calls, attribute accesses, indexing, etc. of Python objects by default automatically convert their result to a Julia type. InPythonCallthe default is to always returnPyObject. The latter behaviour provides type-stability. It also makes interacting with Python values more predictable and allows generic programming (where the type of the result is not known). It also allows the user to pick another type to convert to after the fact, whereas sincePyCallconversion can be lossy, this is sometimes not possible there. - Building.
PyCalllocates libpython in its build step, so that it is aconstin the module code. This makesccalls and the like straightforward.PythonCalldoes this at run-time, which slightly complicates the code (although it is abstracted away) but means that the module does not need to be rebulit for different Python versions. - Default Python. By default
PyCalluses the version of Python incondaand will silently installminicondafor you if it doesn't exist.PythonCallby default simply uses the version of Python in the PATH. Both are customizable through environment variables. - Python modules.
PyCallhas a companion Python modulejuliafor calling Julia from Python. So doesPythonCall, but calledjuliacall. Both of them usePyCall/PythonCallunder the hood on the Julia side. ThePyCallone is itself about as complex in implementation asPyCall. ThePythonCallone is about 50 lines of code (essentially just finding and loading libjulia and the PythonCall module) and provides a single simple entrypoint: the juliaMainmodule. - Compatability.
PyCallsupports Julia 0.7+ and Python 2.7+, whereasPythonCallsupports Julia 1.0+ and Python 3.5+.PyCallrequiresnumpyto be installed,PythonCalldoesn't (it provides the same fast array access through the buffer protocol and array interface). - Startup time.
PythonCalltakes longer to start thanPyCall, largely because there are a lot of wrapper types (juliacall.AnyValueetc.) to compile.