Skip to content

Commit 73bc4ab

Browse files
author
Christopher Doris
committed
docs
1 parent ed0ab63 commit 73bc4ab

File tree

2 files changed

+11
-0
lines changed

2 files changed

+11
-0
lines changed

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ makedocs(
1010
"juliapy.md",
1111
"conversion.md",
1212
"compat.md",
13+
"pycall.md",
1314
]
1415
)
1516

docs/src/pycall.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Comparison to PyCall
2+
3+
The existing package [`PyCall`](https://github.com/JuliaPy/PyCall.jl) is another similar interface to Python. Here is a comparison of the designs:
4+
- **Flexibility of conversion.** The mechanisms for data conversion from Python to Julia are different. In `PyCall`, conversion to `T` (via `convert(T,::PyObject)`) essentially only takes `T` into account, so for example when `T=Real` then the input will always be converted to a Python `float`, which is then converted to a `Cdouble`. In `Python`, conversion takes into account both the target type `T` and 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 in `Python`, converting to a `Real` might return an `Int` (e.g. the input is a `int`), or `Cdouble` (e.g. the input is `float`), or `Rational{BigInt}`, or...
5+
- **Lossiness of conversion from Python.** In `PyCall`, the default `PyAny` conversion 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 a `Vector{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, since `Vector` and `list` have different indexing semantics. In `Python`, the default conversion is to `PyObject` (non-lossy), and even if you convert to `Any` then by default this will be non-lossy: for example a `list` will be converted to a `PyList` which is a `Vector`-like view of the list.
6+
- **Lossiness of conversion to Python.** Similarly, in `PyCall` the default conversion from Julia to Python can be lossy: a `Vector{Int}` will be converted to a `list` of `int`s for example, losing mutability of the original vector. In `Python`, only immutable values are truly converted to Python, everything else is wrapped into a Python wrapper around the Julia value: a `Vector{Int}` is wrapped into a `julia.VectorValue` which is a `list`-like sequence type
7+
- **Automatic conversion.** In `PyCall`, most function calls, attribute accesses, indexing, etc. of Python objects by default automatically convert their result to a Julia type. In `Python` the default is to always return `PyObject`. 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 since `PyCall` conversion can be lossy, this is sometimes not possible there.
8+
- **Building.** `PyCall` locates libpython in its build step, so that it is a `const` in the module code. This makes `ccall`s and the like straightforward. `Python` does 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.
9+
- **Default Python.** By default `PyCall` uses the version of Python in `conda` and will silently install `miniconda` for you if it doesn't exist. `Python` by default simply uses the version of Python in the PATH. Both are customizable through environment variables.
10+
- **Python modules.** `PyCall` has a companion Python module `julia` for calling Julia from Python. So does `Python`. Both of them use `PyCall`/`Python` under the hood on the Julia side. The `PyCall` one is itself about as complex in implementation as `PyCall`. The `Python` one is about 50 lines of code (essentially just finding and loading libjulia and the Python module) and provides a single simple entrypoint: the julia `Main` module.

0 commit comments

Comments
 (0)