Jython is the correct way to instantiate a class and execute methods from a Python class

I have a Python file that contains a class. I need to create an instance of this class and be able to call methods using Java.

I came up with a solution like this:

    PythonInterpreter r = new PythonInterpreter();
    r.execfile("File.py");


    PyObject p = r.eval("Car().begin()");
    System.out.println(p.toString());

      

And the python code:

class Car(SomeExtendedClass):

    myvar = 5

    def set(self, my):
        self.myvar = my;

    def begin(self):
        return self.myvar

      

Now when I execute this it prints 5

But if I run the following code:

    PyObject p = r.eval("Car().begin()");
    System.out.println(p.toString());

    r.eval("Car().set(7)");

    p = r.eval("Car().begin()");

    System.out.println(p.toString());

      

It will still print 5

instead of7

Looks like I didn't create one instance Car

and it always created a new instance instead of using the created one.

I'm right?

Is it possible to create a new instance from a class in a Python file and call / get data from methods from Java?

I tried loading PyInstance

with help eval()

, but I can't tell the exception from it:

return (PyInstance) this.interpreter.eval(className);

      

+3


source to share


2 answers


Whenever you call Car()

, you create a new instance of the class. So this creates a new object and calls its set method:

r.eval("Car().set(7)");

      

But this creates another instance instead of manipulating the existing one:

p = r.eval("Car().begin()");

      

The call r.eval("Car().begin()");

creates a new python object as needed, but it actually returns a reference to the python object containing the return value from the method begin()

, not the instantiated one. This is not what you wanted.

Leaving the python class exactly as defined, this code gets a reference to one instance of the class:

PyObject p = r.eval("Car()");

      



(As you've already seen, the alternative is to omit the parenthesis, which gives you a reference to the python class object, and then use __call__

it to instantiate it).

Then call the method on the existing instance:

p.invoke("set", Py.newInteger(7));

      

To get the modified value, since it is an instance attribute and is not available with the "getter" method, the getattr method of the PyObject class can get to it (or you can add a get method to the python code):

System.out.println(p.__getattr__("myvar"));

      

It's a shame that once you get a reference to an object through p

, you can't just call a method on it with java syntax, but of course Java doesn't know anything about the methods and / or attributes available on a Python object, and even if it were perhaps they could change at any time due to the dynamic nature of Python. This leaves you with methods invoke

for tying Java / Python together.

+1


source


I just found a solution for this "mystery"

First, we want to execute the python file from which we are going to get the instances:

r.execfile("File.py");

      

And then define PyObject

which will contain the class you want to call:

PyObject car = r.get("Car");

      

And then you have to call the method __call__

to create a new instance Car

and pass it to PyObjectDerived

:

PyObjectDerived p = (PyObjectDerived) o.__call__();

      



Now you can call methods like:

Python code:

def set(self, my):
    self.myvar = my;

      

Your java call:

p.invoke("set", Py.newInteger(5));

      

Hope I helped someone.

+2


source







All Articles