Подтвердить что ты не робот

Jython, используйте только метод из Python с Java?

При чтении и использовании этой статьи предполагается, что у нас есть полное определение объекта с объектами класса и сопоставления (прокси) от python до java.

Можно ли импортировать метод (не определенный внутри класса, но используя внутренний класс python) из куска кода в python без его обертывания в определении класса (без использования парадигмы factory, описанной выше).

Мне хотелось бы сделать какой-то from myPyFile import myMethod из java, а затем использовать myMethod, непосредственно из java (возможно, как статический метод?)? Но если это возможно, я не нашел ни малейшего понятия о том, как это сделать (материал интерфейса, описанный в статье, может быть еще необходим, чтобы сказать Java, как использовать myMethod?)

С уважением.

EDIT: теперь я имею дело с Jython 2.5.2, поэтому он может быть зависимым от версии и намного проще в будущем?

РЕДАКТИРОВАТЬ: Ниже в ответ на Даниэля:

Вот пример кода, чтобы воспроизвести полученную ошибку, а также получить рабочий пример из вашего полезного ответа!

(Ну и добавьте немного другого вопроса о отображении обратно в объекты Java из результата, полученного Python/Jython)

(@Joonas, Извините, я изменил свой код, и теперь я не могу вернуться к ошибке, которую я использовал)

import org.python.core.Py;
import org.python.core.PyList;
import org.python.core.PyTuple;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.core.PySystemState;
import org.python.util.PythonInterpreter;

interface MyInterface {
    public PyList getSomething(String content, String glue, boolean bool);
}
class MyFactory {

    @SuppressWarnings("static-access")
    public MyFactory() {
        String cmd = "from mymodule import MyClass";
        PythonInterpreter interpreter = new PythonInterpreter(null, new PySystemState());

        PySystemState sys = Py.getSystemState();
        sys.path.append(new PyString("C:/jython2.5.2/Lib"));

        interpreter.exec(cmd);
        jyObjClass = interpreter.get("MyClass");
    }

    public MyInterface createMe() {
        PyObject myObj = jyObjClass.__call__();
        return (MyInterface)myObj.__tojava__(MyInterface.class);
    }

    private PyObject jyObjClass;
}


public class Main {

    public static void main(String[] args) {

    /*
// with only :
    PythonInterpreter interpreter = new PythonInterpreter();

     i get : 
Exception in thread "main" Traceback (most recent call last):
  File "<string>", line 1, in <module>
LookupError: no codec search functions registered: can't find encoding 'iso8859_1'

which is probably due to the : 
#!/usr/bin/env python
# -*- coding: latin-1 -*-

// yes i am from France, so my - sorry for that - bad english ;) and have to deal with non 127 ascii chars :)
     */

    PythonInterpreter interpreter = new PythonInterpreter(null, new PySystemState());

    PySystemState sys = Py.getSystemState();
    sys.path.append(new PyString("C:/jython2.5.2/Lib"));

    interpreter.exec("from mymodule import getSomething"); 
    PyObject tmpFunction = interpreter.get("getSomething"); 
    System.err.println(tmpFunction.getClass()); 
    MyInterface i = (MyInterface) tmpFunction.__tojava__(MyInterface.class); 
    System.err.println(i.getSomething("test", " - ", true));
    for (Object x : i.getSomething("test", " - ", true)) {
        System.out.println(x);
        // How can i get back an equivallent of the Python _"for (a, b) in getSomething:"_ 
        // with _"a"_ being PyUnicode or better String, and _"b"_ being boolean ?
    }

    // ^^ so adapting Daniel Teply solution works ! Thanks to him... 
    // BTW the part below did not work : but i may have missed or/and also mixed many things :/
    // i feel Jython damned hard to dive in :/ 
    // and really hope that the sample that i post and answers that i get will help others to swim!

    try {
        MyFactory factory = new MyFactory();
        MyInterface myobj = factory.createMe();

        PyList myResult = myobj.getSomething("test", " - ", true);
        System.out.println(myResult);
    }
    catch (Exception e) {
        System.out.println(e);
        // produce a : java.lang.ClassCastException: org.python.core.PySingleton cannot be cast to MyInterface
        // EDIT : see below last edit, this error may be due to my forgotten heritage from interface in the python code!
    }

    System.exit(-1);
    }
}

Часть Python: (mymodule.py)

#!/usr/bin/env python
# -*- coding: latin-1 -*-

class MyClass:
    def __init__(selfself):
        pass
    def getSomething(self, content, glue = '', bool = True):
        for x in range(5):
            yield (glue.join(map(str, (content, x, chr(97 + x))))), bool
        #return list()

def getSomething(content, glue = '', bool = True):
    print "test"
    myclass = MyClass()
    return list(myclass.getSomething(content, glue, bool))

def main():
    test()

if __name__ == "__main__":
    main()

ИЗМЕНИТЬ:

Частично отвечая на меня, для внутреннего вопроса (внутри комментариев):
(на самом деле я чувствую, что мой ответ и код уродливы, но он работает, и, похоже, все в порядке, чтобы не корпеть. Я не знаю, есть ли лучший способ для Jythonic, если это так, мне действительно интересно:))

for (Object x : i.getSomething("test", " - ", true)) {
    System.out.println(x);
    // How can i get back an equivallent of the Python _"for (a, b) in getSomething:"_ 
    // with _"a"_ being PyUnicode or better String, and _"b"_ being boolean ?

    // answering myself here :
    PyTuple mytuple = (PyTuple) x; // casting back x as PyTuple, can we have a java equivalent to _`(a, b) = x_ ? not sure...
    PyObject a = mytuple.__getitem__(0);
    PyObject b = mytuple.__getitem__(1);
    String aS = a.toString(); // mapping a unicode python string to java is as simple?
    boolean bB = b.toString().toLowerCase().equals("true");
    System.out.println(mytuple + "[" + aS + "][" + b + "][" + bB + "]");


РЕДАКТИРОВАТЬ:

Отвечая на вопрос о "production a:" java.lang.ClassCastException: org.python.core.PySingleton нельзя отнести к MyInterface "... большинство моих недоразумений и ошибок, из-за того, что я забыл обработать Java из части Python! (см. мой код выше, я оставляю его не исправленным об этом факте, потому что это не мой главный вопрос и в его реальной форме это рабочий ответ об этом главном вопросе, большое спасибо Даниэлю и Джоонасу, который помогли мне понять). Итак, для парадигмы factory следует НЕ забыть добавить адекватный импорт в свой файл Python:

from testjython.interfaces import MyInterface #// defining method inside a MyInterface.java

class MyClass(MyInterface):
    [...]

Еще одна проблема, с которой я столкнулся, - правильно обрабатывать импорт и пакеты. BTW, добавив этот код в верхний код, вы получите TypeError: невозможно преобразовать в org.python.core.PyList, но это еще одна проблема...

4b9b3361

Ответ 1

Вы можете использовать PyObject.__call__(Object... args) для вызова любого вызываемого объекта Python. Вы можете получить PyFunction, представляющий вашу функцию со стороны java, так же, как вы, например, получаете класс сотрудника python.

Alternativeley, вы можете скрыть это за единственным интерфейсом метода на стороне java, вызвав __tojava__(Interface.class) для функции, которую вы получили из интерпретатора Python. Подробный пример (фактически проверенный!): Файл python:

def tmp():
    return "some text"

Java:

public interface I{
    public String tmp();
}

public static void main(String[] args) {
    PythonInterpreter interpreter = new PythonInterpreter();
    interpreter.exec("from test import tmp");
    PyObject tmpFunction = interpreter.get("tmp");
    System.err.println(tmpFunction.getClass());
    I i = (I) x.__tojava__(I.class);
    System.err.println(i.tmp());

}

выход:

class org.python.core.PyFunction
some text

Ответ 2

Импорт только метода невозможен, поскольку в Java методы (или функции) не являются первоклассными объектами, то есть нет способа ссылаться на метод, не обращаясь сначала к некоторому классу (или интерфейсу). Даже статические методы заключены в класс, и вы ссылаетесь на них через объект класса.

Тем не менее, вы можете получить довольно близкое решение с помощью встроенного в Jython 2.5.2: функции Jython работают непосредственно как реализации одного абстрактного метода Java-интерфейсов (см. http://www.zyasoft.com/pythoneering/2010/09/jython-2.5.2-beta-2-is-released/). Таким образом, вы можете определить интерфейс в Java - важно, чтобы он содержал ровно одно определение метода:

interface MyInterface {
    int multiply(int x, int y);
}

Плюс что-то подобное в Jython:

myFunction = lambda x, y : x * y

и использовать это как MyInterface в Java. Вам все равно придется использовать какой-то шаблон factory, как описано в статье, с которой вы связались, чтобы получить Jython-функцию на Java, но что-то вроде этого работает (вероятно, содержит ошибки, но идея есть):

PyObject myFunction = interpreter.get("myFunction"); 
MyInterface myInterface = (MyInterface)myFunction.__tojava__(MyInterface.class);
int x = myInterface.multiply(2, 3); // Should return 6.