Use Python from Java with Jython. I was also addicted to it.

Jython allows you to run Python scripts on the JVM. Is there anyone who uses it? You might think, but it's me. I'm here.

Jython

Originator http://www.jython.org/ wikipedia https://ja.wikipedia.org/wiki/Jython

I will write how to use (Java code) and addictive points.

Python script execution from Java

When I googled it, I got the impression that there are many ways to install it and use it from the command line, but this time I will run it from Java code.

First maven pom.xml

pom.xml


		<dependency>
			<groupId>org.python</groupId>
			<artifactId>jython-standalone</artifactId>
			<version>2.7.0</version>
		</dependency>

Simple python script execution


import java.util.Properties;
import org.python.util.PythonInterpreter;

//・ ・ ・

	public static void main(String[] args) {
		Properties props = new Properties();
		props.put("python.console.encoding", "UTF-8");

		PythonInterpreter.initialize(System.getProperties(), props, new String[0]);
		try (PythonInterpreter interp = new PythonInterpreter()) {

			interp.exec("a = 1 + 2");
			interp.exec("print(a)");
		}
	}

Result (console)

3

I wasn't sure exactly what python.console.encoding was, but I got an error if it wasn't there, so when I googled it, I wrote it like this.

Exchange variables with Python scripts

import org.python.core.PyInteger;
import org.python.core.PyObject;

//・ ・ ・
	public static void main(String[] args) {
		Properties props = new Properties();
		props.put("python.console.encoding", "UTF-8");

		PythonInterpreter.initialize(System.getProperties(), props, new String[0]);
		try (PythonInterpreter interp = new PythonInterpreter()) {
			PyInteger x = new PyInteger(10);
			interp.set("x", x);//Substitute 10 for x
			interp.exec("a = x + 2");

			PyObject a = interp.get("a");//Get the result of a

			System.out.println(a);
			System.out.println(a.getClass());
		}
	}

result

12
class org.python.core.PyInteger

There are various implementation classes of PyObject, and you can set and get them to exchange Java code and Python code.

PyInteger if you want to pass int, PyString if you want to pass str ... I think Japanese people are addicted to it here. See next.

	PyString s = new PyString("AIUEO");

When I try to generate a PyString with the string " AIUEO ", it looks like this.

Exception in thread "main" java.lang.IllegalArgumentException: Cannot create PyString with non-byte value
	at org.python.core.PyString.<init>(PyString.java:64)
	at org.python.core.PyString.<init>(PyString.java:70)
at ....main(・ ・ ・ ・)

Gununu. The first thing to understand is that Jython has Python 2 support. Python3 code does not work. (I was studying only Python3 so I was disappointed)

Fighting strings and Jython

Python2 had to be unicode. So

	public static void main(String[] args) {
		Properties props = new Properties();
		props.put("python.console.encoding", "UTF-8");

		PythonInterpreter.initialize(System.getProperties(), props, new String[0]);
		try (PythonInterpreter interp = new PythonInterpreter()) {
			PyUnicode s = new PyUnicode("AIUEO");
			interp.set("s", s);
			interp.exec("a = s * 10");

			PyObject a = interp.get("a");

			System.out.println(a);
			System.out.println(a.getClass());
		}
	}
Aiue Aiue Aiue Aiue Aiue Aiue Aiue Aiue Aiue Aiue Aiue
class org.python.core.PyUnicode

I was able to do it.

I want to handle it with str on Python

Encode it on a Python script and handle it with str.

	public static void main(String[] args) {
		Properties props = new Properties();
		props.put("python.console.encoding", "UTF-8");

		PythonInterpreter.initialize(System.getProperties(), props, new String[0]);
		try (PythonInterpreter interp = new PythonInterpreter()) {
			PyUnicode s = new PyUnicode("AIUEO");
			interp.set("s", s);
			interp.exec("s = s.encode('utf-8')");
			interp.exec("a = s * 10");

			PyObject a = interp.get("a");

			System.out.println(a);
			System.out.println(a.getClass());
		}
	}

あいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえおあいうえお
class org.python.core.PyString

Somehow I was expecting it. Rewrite

	public static void main(String[] args) {
		Properties props = new Properties();
		props.put("python.console.encoding", "UTF-8");

		PythonInterpreter.initialize(System.getProperties(), props, new String[0]);
		try (PythonInterpreter interp = new PythonInterpreter()) {
			PyUnicode s = new PyUnicode("AIUEO");
			interp.set("s", s);
			interp.exec("s = s.encode('utf-8')");
			interp.exec("a = s * 10");
			interp.exec("a = a.decode('utf-8')");

			PyObject a = interp.get("a");

			System.out.println(a);
			System.out.println(a.getClass());
		}
	}
Aiue Aiue Aiue Aiue Aiue Aiue Aiue Aiue Aiue Aiue Aiue
class org.python.core.PyUnicode

It was OK if I decoded it to unicode before taking the variable.

Error in upper

	public static void main(String[] args) {
		Properties props = new Properties();
		props.put("python.console.encoding", "UTF-8");

		PythonInterpreter.initialize(System.getProperties(), props, new String[0]);
		try (PythonInterpreter interp = new PythonInterpreter()) {
			PyUnicode s = new PyUnicode("a ah");
			interp.set("s", s);
			interp.exec("s = s.encode('utf-8')");
			interp.exec("a = s.upper()");
			interp.exec("a = a.decode('utf-8')");

			PyObject a = interp.get("a");

			System.out.println(a);
			System.out.println(a.getClass());
		}
	}

Where to expect the result ʻA a`

Exception in thread "main" Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "・ ・ ・\repository\org\python\jython-standalone\2.7.0\jython-standalone-2.7.0.jar\Lib\encodings\utf_8.py", line 16, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 3: unexpected code byte

When I upper it on Python, it seems to be an error because it is new PyString () and contains multibyte characters. maybe. It seems that there is no workaround here other than writing the code carefully. You should use unicode instead of str. (Please point out if there is a method) But if it's used in an external Python library, it can't be helped. Wonder? .. .. ..

Loading external Python library (directory)

Create the following py file in some directory

sample.py


# coding:utf-8
def add_numbers(a, b):
	return a + b

Load and execute this

	public static void main(String[] args) {
		Properties props = new Properties();

		props.put("python.path", "[Sample above.Directory with py]");
		props.put("python.console.encoding", "UTF-8");

		PythonInterpreter.initialize(System.getProperties(), props, new String[0]);
		try (PythonInterpreter interp = new PythonInterpreter()) {
			interp.exec("import sample"); //sample.import py
			interp.exec("a = sample.add_numbers(2, 3)");
			interp.exec("print(a)");
		}
	}
5

Set the directory to python.path. If there are multiple, it seems that it can be handled by connecting them with a delimiter. (Windows ;) http://www.jython.org/archive/22/userfaq.html#my-modules-can-not-be-found-when-imported-from-an-embedded-application

Loading external Python library (in jar)

You can also run the py file in the jar.

How to specify Specify [Path.jar with Jar] \ [folder name in jar with py file].

If there is a py file in a folder called python in the jar, write it like this.

props.put("python.path", "C:/・ ・ ・ ・.jar/python");

If you know that it exists in the python folder, you can write it like this.

	public static void main(String[] args) {
		Properties props = new Properties();

		props.put("python.path", getPythonPath());
		props.put("python.console.encoding", "UTF-8");

		PythonInterpreter.initialize(System.getProperties(), props, new String[0]);
		try (PythonInterpreter interp = new PythonInterpreter()) {
			interp.exec("import sample");
			interp.exec("a = sample.add_numbers(2, 3)");
			interp.exec("print(a)");
		}
	}

	private static String getPythonPath() {
		try {
			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			URL root = classLoader.getResource("python");

			if ("file".equals(root.getProtocol())) {
				Path path = Paths.get(root.toURI());
				return path.toString();
			} else if ("jar".equals(root.getProtocol())) {
				URI jarFileUri = new URI(root.getPath().replaceFirst("!/.*$", ""));
				Path path = Paths.get(jarFileUri);
				return path.resolve("python").toString();
			}
		} catch (URISyntaxException e) {
			throw new IllegalStateException(e);
		}
		throw new IllegalStateException("python directory not found");
	}

This allows you to run both flat py files and jar-packed py files. Now you don't have to rewrite the code for development and deployment.


Finally

Summary of addictive points

First of all, I have to study the 2nd system. .. ..

Recommended Posts

Use Python from Java with Jython. I was also addicted to it.
I was addicted to scraping with Selenium (+ Python) in 2020
[IOS] GIF animation with Pythonista3. I was addicted to it.
I want to use jar from python
What I was addicted to Python autorun
What I was addicted to with json.dumps in Python base64 encoding
I want to tweet on Twitter with Python, but I'm addicted to it
[Introduction to json] No, I was addicted to it. .. .. ♬
A story I was addicted to when inserting from Python to a PostgreSQL table
I was addicted to creating a Python venv environment with VS Code
I want to use Temporary Directory with Python2
I want to use ceres solver from python
I tried to use Java with Termux using Termux Arch but it didn't work
Three things I was addicted to when using Python and MySQL with Docker
I was able to mock AWS-Batch with python, moto, so I will leave it
A note I was addicted to when running Python with Visual Studio Code
A story that I was addicted to when I made SFTP communication with python
I wanted to use the Python library from MATLAB
I was able to repeat it in Python: lambda
What I was addicted to when using Python tornado
I was soberly addicted to calling awscli from a Python 2.7 script registered in crontab
[Python] I want to use the -h option with argparse
What I was addicted to when migrating Processing users to Python
[Fixed] I was addicted to alphanumeric judgment of Python strings
Python: How to use async with
Create folders from '01' to '12' with python
I made a server with Python socket and ssl and tried to access it from a browser
How to use FTP with Python
I want to debug with Python
I was addicted to multiprocessing + psycopg2
A story that I was addicted to calling Lambda from AWS Lambda.
I want to use a wildcard that I want to shell with Python remove
What I was addicted to when introducing ALE to Vim for Python
A note I was addicted to when creating a table with SQLAlchemy
I read "Reinforcement Learning with Python: From Introduction to Practice" Chapter 1
Python> Comprehension> cells> I was taught how to use double comprehension / itertools
I was addicted to confusing class variables and instance variables in Python
I read "Reinforcement Learning with Python: From Introduction to Practice" Chapter 2
When I tried to use pip with python, I was told that XML_SetHashSalt could not be found.
I was addicted to not being able to get an email address from google with django-allauth authentication
Why I moved from Java to Dart
I wanted to solve ABC160 with Python
[Introduction to Python] Let's use foreach with Python
I want to analyze logs with Python
I was addicted to Flask on dotCloud
I want to play with aws with python
Use C ++ functions from python with pybind11
I wanted to solve ABC172 with Python
I was able to print the thermal printer "PAPERANG" from Python (Windows10, Python3.6)
I want to do it with Python lambda Django, but I will stop
When I tried to run Python, it was skipped to the Microsoft Store
I was addicted to running tensorflow on GPU with NVIDIA driver 440 + CUDA 10.2
A story I was addicted to trying to get a video url with tweepy
I was addicted to not being able to use Markdown on pypi's long_description
The file name was bad in Python and I was addicted to import
[Python] I was hooked for an hour trying to use list comprehensions
[Python] I was addicted to not saving internal variables of lambda expressions
[Python] It was very convenient to use a Python class for a ROS program.
[Zaif] I tried to make it easy to trade virtual currencies with Python
I started machine learning with Python (I also started posting to Qiita) Data preparation
I was addicted to trying Cython with PyCharm, so make a note