14

在阅读和使用本文时,假设我们有一个完整的对象定义,其中包含从 python 到 java 的类和映射(代理)对象。

是否可以只从 python 中的一段代码导入一个方法(不是在类内部定义,而是使用内部 python 类)而不将其包装在类定义中(不使用上述工厂范式)。

我想从java做一些事情from myPyFile import myMethod,然后直接从java使用myMethod(也许作为静态方法?)?但是如果这是可能的,我没有找到任何线索来说明如何做到这一点(文章中描述的接口内容可能仍然需要告诉 Java 如何使用 myMethod ?)

此致。

编辑:我现在正在处理Jython 2.5.2,所以它可能依赖于版本并且将来会更容易吗?

编辑:下面回复丹尼尔:

这是一个示例代码,用于重现我得到的错误,并从您的有用回复中获得一个工作示例!

(好吧,在从yield -ed Python/Jython 结果映射回 Java 对象时添加一点其他问题)

(@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 + "]");


编辑:

回答自己关于“产生一个:”java.lang.ClassCastException:org.python.core.PySingleton 不能转换为 MyInterface”的部分......我的大部分误解和错误是由于我忘记了从 Python 部分处理 Java!(参见我上面的代码,我没有更正这个事实,因为这不是我的主要问题,并且在实际形式中,它是关于这个主要问题的有效答案,非常感谢 Daniel 和帮助我理解的 Joonas)。因此对于工厂范式,不应忘记将适当的导入添加到其 Python 文件中:

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

class MyClass(MyInterface):
    [...]

我遇到的另一个困难是正确处理导入和包。顺便说一句,将此代码添加到上面的代码会产生TypeError: can't convert to org.python.core.PyList但这是另一个问题......

4

2 回答 2

7

You can use PyObject.__call__(Object... args) to invoke any callable Python object. You can get the PyFunction representing your function from the java side the same way you example is getting the python employee class.

Alternativeley, you can hide this behind a single method interface on the java side by calling __tojava__(Interface.class) on the function you retrieved from the Python interpreter. Detailed example (actually tested!): python file:

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());

}

output:

class org.python.core.PyFunction
some text
于 2012-05-10T15:35:12.877 回答
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

并将其用作MyInterfaceJava 中的 a 。您仍然必须使用某种工厂模式,如您链接到的文章中所述,将 Jython 函数获取到 Java,但是这样的工作(可能包含错误,但想法是):

PyObject myFunction = interpreter.get("myFunction"); 
MyInterface myInterface = (MyInterface)myFunction.__tojava__(MyInterface.class);
int x = myInterface.multiply(2, 3); // Should return 6.
于 2012-05-10T09:52:07.020 回答