16. Python interoperability

As mentioned in the beginning of this book, Mojo is very close to Python in terms of syntax. However, Mojo and Python are semantically two completely different languages, though they share very similar syntax. Python has a huge ecosystem behind it, built over many decades. Mojo allows the developer to leverage this huge ecosystem, with its Python integration capability.

The integration of Mojo with Python is built on a key insight that from a practical point of view, all Python objects can be represented with a single type. In Mojo it is represented by the PythonObject struct. Mojo uses the actual CPython interpreter for interoperability. The usage of CPython in Mojo enables high fidelity integration with Python, and ensures that the Python objects behave as expected.

16.1. Importing a Python module

Mojo has module named python that encapsulates all of the Python integration. Within the python module, there is the facade object that provides the entry point for many of the Python integration capabilities.

Importing a Python module is as simple as using the Python.import_module method call, passing it the module name. In case a module does not exist, ensure that the module is installed using the pip or equivalent command. Mojo also supports Python virtual environments.

The following code listing provides an example on how to import Python modules and how to use objects from Python.

    from python import Python
    var difflib = Python.import_module("difflib")
    var list1 = ["One", "Two", "Three", "Four"]
    var list2 = ["One", "Two", "Three"]
    var differ = difflib.HtmlDiff() # Get instance of HtmlDiff class.
    var diff = differ.make_file(list1, list2)
    print(diff)

16.2. Evaluating Python expressions

You can evaluate Python expressions using Python.evaluate method.

    print(Python.evaluate("1+2"))

Since Python treats functions as first class, you can even use Python.evaluate to access Python’s built-in functions.

    var str_fn = Python.evaluate("str")
    print(str_fn("ABC") <= str_fn("XYZ"))

Note in the above code listing, how transparently we can transfer Mojo string literals to the Python function, and how seamlessly Mojo operators work over Python objects, invoking the right Python dunder methods. One important constraint is that only PythonObject struct can be passed to and from Python. In the case of Mojo string literals, PythonObject has a constructor that takes StringLiteral, resulting in implicit conversion from StringLiteral to a PythonObject instance. PythonObject has many such constructors for the various Mojo built-in types. PythonObject also implements many traits that enable it to be used within functions such as len, int, str and so on.

16.3. Other useful Python functions

You can use native Python objects like list and dict using corresponding static methods exposed by Python. Python also exposes type function from Python and can be used to determine the underlying type of the PythonObject struct.

    var a_list = Python.list()
    a_list.append("First element")
    a_list.append("Second element")
    print(a_list)
    print(Python.type(a_list))