The reticulate package provides an R interface to Python modules, classes, and functions. For example, this code imports the Python os
module and calls some functions within it:
library(reticulate)
os <- import("os")
os$chdir("tests")
os$getcwd()
Functions and other data within Python modules and classes can be accessed via the $
operator (analogous to the way you would interact with an R list, environment, or reference class).
The reticulate package is compatible with all versions of Python >= 2.7. Integration with NumPy is optional and requires NumPy >= 1.6.
When calling into Python, R data types are automatically converted to their equivalent Python types. When values are returned from Python to R they are converted back to R types. Types are converted as follows:
R | Python | Examples |
---|---|---|
Single-element vector | Scalar | 1 , 1L , TRUE , "foo" |
Multi-element vector | List | c(1.0, 2.0, 3.0) , c(1L, 2L, 3L) |
List of multiple types | Tuple | list(1L, TRUE, "foo") |
Named list | Dict | list(a = 1L, b = 2.0) , dict(x = x_data) |
Matrix/Array | NumPy ndarray | matrix(c(1,2,3,4), nrow = 2, ncol = 2) |
Function | Python function | function(x) x + 1 |
NULL, TRUE, FALSE | None, True, False | NULL , TRUE , FALSE |
If a Python object of a custom class is returned then an R reference to that object is returned. You can call methods and access properties of the object just as if it was an instance of an R reference class.
The import
function can be used to import any Python module. For example:
difflib <- import("difflib")
difflib$ndiff(foo, bar)
filecmp <- import("filecmp")
filecmp$cmp(dir1, dir2)
The import_main()
and import_builtins()
functions give you access to the main module where code is executed by default and the collection of built in Python functions. For example:
main <- import_main()
py <- import_builtins()
py$print('foo')
The main module is generally useful if you have executed Python code from a file or string and want to get access to it’s results (see the section below for more details).
By default when Python objects are returned to R they are converted to their equivalent R types. However, if you’d rather make conversion from Python to R explicit and deal in native Python objects by default you can pass convert = FALSE
to the import
function. In this case Python to R conversion will be disabled for the module returned from import
. For example:
# import numpy and specify no automatic Python to R conversion
np <- import("numpy", convert = FALSE)
# do some array manipulations with NumPy
a <- np$array(c(1:4))
sum <- a$cumsum()
# convert to R explicitly at the end
py_to_r(sum)
As illustrated above, if you need access to an R object at end of your computations you can call the py_to_r()
function explicitly.
You can execute Python code within the main module using the py_run_file
and py_run_string
functions. These functions both return a reference to the main Python module so you can access the results of their execution. For example:
py_run_file("script.py")
main <- py_run_string("x = 10")
main$x
You can print documentation on any Python object using the py_help()
function. For example:
os <- import("os")
py_help(os$chdir)
The automatic conversion of R types to Python types works well in most cases, but occasionally you will need to be more explicit on the R side to provide Python the type it expects.
For example, if a Python API requires a list and you pass a single element R vector it will be converted to a Python scalar. To overcome this simply use the R list
function explicitly:
foo$bar(indexes = list(42L))
Similarly, a Python API might require a tuple
rather than a list. In that case you can use the tuple()
function:
tuple("a", "b", "c")
R named lists are converted to Python dictionaries however you can also explicitly create a Python dictionary using the dict()
function:
dict(foo = "bar", index = 42L)
This might be useful if you need to pass a dictionary that uses a more complex object (as opposed to a string) as it’s key.
The R with
generic function can be used to interact with Python context manager objects (in Python you use the with
keyword to do the same). For example:
py <- import_builtins()
with(py$open("output.txt", "w") %as% file, {
file$write("Hello, there!")
})
This example opens a file and ensures that it is automatically closed at the end of the with block. Note the use of the %as%
operator to alias the object created by the context manager.
If a Python API returns an iterator or generator you can interact with it using the iterate()
function. The iterate()
function can be used to apply an R function to each item yielded by the iterator:
iterate(iter, print)
If you don’t pass a function to iterate
the results will be collected into an R vector:
results <- iterate(iter)
Note that the Iterators
will be drained of their values by iterate()
:
a <- iterate(iter) # results are not empty
b <- iterate(iter) # results are empty since items have already been drained
You can also iterate on an element-by-element basis using the iter_next()
function. For example:
while (TRUE) {
item <- iter_next(iter)
if (is.na(item))
break
}
By default iter_next()
will return NA
when the iteration is complete but you can provide a custom value and it will be returned instead. For example:
while (TRUE) {
item <- iter_next(iter, completed = NULL)
if (is.null(item))
break
}
Note that some iterators/genrators in Python are infinite. In that case the caller will need custom logic to determine when to terminate the loop.
There are several more advanced functions available that are useful principally when creating high level R interfaces for Python libraries.
Typically interacting with Python objects from R involves using the $
operator to access whatever properties for functions of the object you need. When using the $
, Python objects are automatically converted to their R equivalents when possible. The following functions enable you to interact with Python objects at a lower level (e.g. no conversion to R is done unless you explicitly call the py_to_r
function):
Function | Description |
---|---|
py_has_attr() |
Check if an object has a specified attribute. |
py_get_attr() |
Get an attribute of a Python object. |
py_set_attr() |
Set an attribute of a Python object. |
py_list_attributes() |
List all attributes of a Python object. |
py_call() |
Call a Python callable object with the specified arguments. |
py_to_r() |
Convert a Python object to it’s R equivalent |
r_to_py() |
Convert an R object to it’s Python equivalent |
The following functions enable you to query for information about the Python configuration available on the current system.
Function | Description |
---|---|
py_available() |
Check whether a Python interface is available on this system. |
py_numpy_available() |
Check whether the R interface to NumPy is available (requires NumPy >= 1.6) |
py_module_available() |
Check whether a Python module is available on this system. |
py_config() |
Get information on the location and version of Python in use. |
These functions enable you to capture or suppress output from Python:
Function | Description |
---|---|
py_capture_output() |
Capture Python output for the specified expression and return it as an R character vector. |
py_suppress_warnings() |
Execute the specified expression, suppressing the display Python warnings. |
The functions provide miscellaneous other lower-level capabilities:
Function | Description |
---|---|
py_unicode() |
Convert a string to a Python unicode object. |
py_str() |
Get the string representation of Python object. |
py_is_null_xptr() |
Check whether a Python object is a null externalptr. |
py_validate_xptr() |
Check whether a Python object is a null externalptr and throw an error if it is. |
The following articles cover additional aspects of using reticulate: