Calling Python in Java?

203,894

Solution 1

Jython: Python for the Java Platform - http://www.jython.org/index.html

You can easily call python functions from Java code with Jython. That is as long as your python code itself runs under jython, i.e. doesn't use some c-extensions that aren't supported.

If that works for you, it's certainly the simplest solution you can get. Otherwise you can use org.python.util.PythonInterpreter from the new Java6 interpreter support.

A simple example from the top of my head - but should work I hope: (no error checking done for brevity)

PythonInterpreter interpreter = new PythonInterpreter();
interpreter.exec("import sys\nsys.path.append('pathToModules if they are not there by default')\nimport yourModule");
// execute a function that takes a string and returns a string
PyObject someFunc = interpreter.get("funcName");
PyObject result = someFunc.__call__(new PyString("Test!"));
String realResult = (String) result.__tojava__(String.class);

As of 2021, Jython does not support Python 3.x

Solution 2

I think there are some important things to consider first with how strong you wish to have the linking between java and python.

Firstly Do you only want to call functions or do you actually want python code to change the data in your java objects? This is very important. If you only want to call some python code with or without arguments, then that is not very difficult. If your arguments are primitives it makes it even more easy. However if you want to have java class implement member functions in python, which change the data of the java object, then this is not so easy or straight forward.

Secondly are we talking cpython or will jython do? I would say cpython is where its at! I would advocate this is why python is so kool! Having such high abstractions however access to c,c++ when needed. Imagine if you could have that in java. This question is not even worth asking if jython is ok because then it is easy anyway.

So I have played with the following methods, and listed them from easy to difficult:

Java to Jython

Advantages: Trivially easy. Have actual references to java objects

Disadvantages: No CPython, Extremely Slow!

Jython from java is so easy, and if this is really enough then great. However it is very slow and no cpython! Is life worth living without cpython I don't think so! You can easily have python code implementing your member functions for you java objects.

Java to Jython to CPython via Pyro

Pyro is the remote object module for python. You have some object on a cpython interpreter, and you can send it objects which are transferred via serialization and it can also return objects via this method. Note that if you send a serialized python object from jython and then call some functions which change the data in its members, then you will not see those changes in java. You just need to remember to send back the data which you want from pyro. This I believe is the easiest way to get to cpython! You do not need any jni or jna or swig or .... You don't need to know any c, or c++. kool huh?

Advantages: Access to cpython, not as difficult as following methods

Disadvantages: Cannot change the member data of java objects directly from python. Is somewhat indirect, (jython is middle man).

Java to C/C++ via JNI/JNA/SWIG to Python via Embedded interpreter (maybe using BOOST Libraries?)

OMG this method is not for the faint of heart. And I can tell you it has taken me very long to achieve this in with a decent method. Main reason you would want to do this is so that you can run cpython code which as full rein over you java object. There are major major things to consider before deciding to try and bread java (which is like a chimp) with python (which is like a horse). Firstly if you crash the interpreter that's lights out for you program! And don't get me started on concurrency issues! In addition, there is allot allot of boiler, I believe I have found the best configuration to minimize this boiler but still it is allot! So how to go about this: Consider that C++ is your middle man, your objects are actually c++ objects! Good that you know that now. Just write your object as if your program as in cpp not java, with the data you want to access from both worlds. Then you can use the wrapper generator called swig (http://www.swig.org/Doc1.3/Java.html) to make this accessible to java and compile a dll which you call System.load(dll name here) in java. Get this working first, then move on to the hard part! To get to python you need to embed an interpreter. Firstly I suggest doing some hello interpreter programs or this tutorial Embedding python in C/C. Once you have that working, its time to make the horse and the monkey dance! You can send you c++ object to python via [boost][3] . I know I have not given you the fish, merely told you where to find the fish. Some pointers to note for this when compiling.

When you compile boost you will need to compile a shared library. And you need to include and link to the stuff you need from jdk, ie jawt.lib, jvm.lib, (you will also need the client jvm.dll in your path when launching the application) As well as the python27.lib or whatever and the boost_python-vc100-mt-1_55.lib. Then include Python/include, jdk/include, boost and only use shared libraries (dlls) otherwise boost has a teary. And yeah full on I know. There are so many ways in which this can go sour. So make sure you get each thing done block by block. Then put them together.

Solution 3

It's not smart to have python code inside java. Wrap your python code with flask or another web framework to make it a microservice. This makes your java program able to call this microservice (e.g. via REST).

This approach is simple and it will save you tons of issues. And the codes are loosely coupled so they are scalable.

Updated on Mar 24th 2020: According to @stx's comment, the above approach is not suitable for massive data transfer between client and server. Here is another approach I recommended: Connecting Python and Java with Rust(C/C++ also ok). https://medium.com/@shmulikamar/https-medium-com-shmulikamar-connecting-python-and-java-with-rust-11c256a1dfb0

Solution 4

Several of the answers mention that you can use JNI or JNA to access cpython but I would not recommend starting from scratch because there are already open source libraries for accessing cpython from java. For example:

Solution 5

GraalVM is a good choice. I've done Java+Javascript combination with GraalVM for microservice design (Java with Javascript reflection). They recently added support for python, I'd give it a try especially with how big its community has grown over the years.

UPDATE June 2021

https://www.graalvm.org/reference-manual/python/ says

GraalVM provides a Python 3.8 compliant runtime. A primary goal of the GraalVM Python runtime is to support SciPy and its constituent libraries, as well as to work with other data science and machine learning libraries from the rich Python ecosystem. At this point, the Python runtime is made available for experimentation and curious end-users.

Share:
203,894
Shahab
Author by

Shahab

Updated on December 25, 2021

Comments

  • Shahab
    Shahab over 2 years

    I am wondering if it is possible to call python functions from java code using jython, or is it only for calling java code from python?

  • Voo
    Voo over 12 years
    Any language that itself can be called from c that is. Well ok python can, but Jython is a much simpler solution there really (or using the PyInterpreter in j6+). It's not that trivial to write the code to call python functions from c.
  • Shahab
    Shahab over 12 years
    I've installed JYthon, or i assume i did, and I keep trying to run the code that you outlined but it highlighted as a mistake. Does the installion of Jython need to go to a specific folder, either in the python or java folders?
  • Shahab
    Shahab over 12 years
    There aren't any error, i'm just having a hard time integrating Jython into Netbeans
  • Voo
    Voo over 12 years
    If there's no error it would work, so that's obviously not the case ;) "Error" does not mean runtime error, could be a compile error as well.
  • Shahab
    Shahab over 12 years
    My bad, it was a poor use of the word. I was trying to add the jython.jar to my project and netbeans. I figured it out though
  • yountae.kang
    yountae.kang over 10 years
    @Voo I imported jython.jar as a external library. but I got an error: Could not find class 'org.python.util.PythonInterpreter'
  • Peter Raeves
    Peter Raeves almost 10 years
    @Voo I installed jpython on Ub14.04 and after adding a bunch of required jar files, I stranded at java.lang.IncompatibleClassChangeError: Implementing class. My Main is doing PythonInterpreter i = new PythonInterpreter(); i.exec("print \"hello world\""); Any idea what might be wrong?
  • Peter Raeves
    Peter Raeves almost 10 years
    @Voo Nvm, I found the error. Looks like I needed to add asm3 instead of asm4
  • nn0p
    nn0p over 9 years
    Is the Python interpreter used by org.python.util.PythonInterpreter Jython or CPython?
  • soulmachine
    soulmachine about 9 years
    Thank you, you save my day!
  • soulmachine
    soulmachine about 9 years
    This works! But I have another question, PyObject obj = interpreter.compile("..."); // a piece of code that contains two functions, myFunc1 and myFunc2, how to call a specified functioin, for example myFunc1
  • Thufir
    Thufir over 7 years
    further info in regards to invoking an actual Python API through PythonInterpreter would be appreciated.
  • subes
    subes about 7 years
    Here a library that lets you write your python scripts once and decide which integration method (Jython, CPython via Jep and Py4j) to use at runtime: github.com/subes/invesdwin-context-python Since each method has its own benefits/drawbacks
  • Derrops
    Derrops about 7 years
    @subes that project looks awesome I wrote this a while ago. I encourage you to write an answer I would upvote it. I dislike the top answer haha because I don't think it provides much useful information outside of a google search.
  • subes
    subes about 7 years
    I created a separate answer
  • Mauricio Gracia Gutierrez
    Mauricio Gracia Gutierrez almost 6 years
    does this answer smell to "this should be the accepted answer" or is it just me ? ;-)
  • Christian Schlichtherle
    Christian Schlichtherle over 5 years
    This project doesn't have any release.
  • subes
    subes about 5 years
    @ChristianSchlichtherle invesdwin-context-python version 1.0.0 is not available; thanks to this little gem: github.com/loewenfels/dep-graph-releaser
  • Flummiboy
    Flummiboy over 4 years
    Python 2 end of Life is 1.1.2020 and Jython only supports Python 2.7. so no Jython is basically dead. Best (simplest) Option is the Jep lib
  • stx
    stx over 4 years
    +1 , but what about the additional performance and communication overhead of creating and parsing back and forth messages on both ends?
  • Peiming Hu
    Peiming Hu over 4 years
    yes, this needs to define an api interface with minimum input/output required. It is not smart to have a lot of data transfter between client/server on the network. If you cannot define such an interface, then this design approach doesn't suits.
  • WestCoastProjects
    WestCoastProjects over 3 years
    jython is long long dormant [/dead]. That's too bad.
  • WestCoastProjects
    WestCoastProjects over 3 years
    I used that for a project 15 years ago and it was murderously complicated. At least use JSON..
  • Paul Verest
    Paul Verest about 3 years
  • Paul Verest
    Paul Verest about 3 years
    Project release are now available, see github.com/invesdwin/invesdwin-context-python/issues/1 , however one should consider number of dependencies this project brings, see github.com/invesdwin/invesdwin-context-python/issues/4