简体   繁体   English

Jython,只使用Java中的Python方法?

[英]Jython, use only a method from Python from Java?

When reading and using this article it assumes that we have a full object definition with class and mapping (proxy) objects from python to java. 在阅读和使用本文时,它假定我们有一个完整的对象定义,其中包含从python到java的类和映射(代理)对象。

Is it possible to only import a method (not defined inside a class, but using internal python class) from a piece of code in python without wrapping it in a class definition (without using the factory paradigm described above). 是否有可能只从python中的一段代码中导入方法(未在类中定义,但使用内部python类),而不将其包装在类定义中(不使用上述工厂范例)。

I would have like to do some kind of from myPyFile import myMethod from java, and then use myMethod, directly from java (maybe as a static method ?) ? 我想from myPyFile import myMethod做一些从java from myPyFile import myMethod ,然后直接从java使用myMethod(也许作为静态方法?)? But if this is possible, I do not have found any clue of how doing that (the interface stuff described in the article may be still necessary to tell Java how to use myMethod ?) 但是,如果这是可能的,我没有找到任何关于如何做的线索(文章中描述的界面东西可能仍然需要告诉Java如何使用myMethod?)

Best regards. 最好的祝福。

EDIT : I am now dealing with Jython 2.5.2 , so it may be version dependent and much more easier in future ? 编辑 :我现在正在处理Jython 2.5.2 ,所以它可能依赖于版本,将来会更容易?

EDIT : Below in reply to Daniel : 编辑:下面回复丹尼尔:

Here is a sample code, to reproduce the error I get, and also get a working example from your helpful reply! 这是一个示例代码,用于重现我得到的错误,并从您有用的回复中获得一个有效的示例!

(Well and add a little other question on the mapping back to Java objects from a yield -ed Python/Jython result) (好吧,在从yield -ed Python / Jython结果返回Java对象的映射中添加一些其他问题)

(@Joonas, Sorry, I have modified my code, and now I am not able to step back to the error that I used to have) (@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 part: (mymodule.py) 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()

EDIT : 编辑

Partially answering myself, for the inner question (inside comments): 部分回答自己,内心问题(内部评论):
(actually I feel my answer and code are ugly, but it works and seems to be ok to un- tuple I do not know if there is a better Jythonic-way to do it, if so, I am really interested :)) (其实我觉得我的答案和代码是丑陋,但它的工作原理,似乎是确定以非元组 ,我不知道是否有更好的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 + "]");


EDIT: 编辑:

Answering myself to the part about "produce a : "java.lang.ClassCastException: org.python.core.PySingleton cannot be cast to MyInterface" ... most of my misunderstanding and errors where due to the fact that I had forgotten to handle the Java from the Python part! (see my code above, I leave it uncorrected about this fact because it was not my main question, and in its actual form, it's a working answer about this main question, many thanks to Daniel and Joonas who helped me to understand). So for the factory paradigm, one should NOT forget to add the adequate import to its Python file : 回答关于“产生一个: 的部分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):
    [...]

One other difficulty that I had was to correctly handle the import and packages. 我遇到的另一个困难是正确处理导入和包。 BTW, adding this code to the upper code will produce a TypeError: can't convert to org.python.core.PyList but this is another concern... 顺便说一句,将此代码添加到上层代码将产生一个TypeError:无法转换为org.python.core.PyList但这是另一个问题......

You can use PyObject.__call__(Object... args) to invoke any callable Python object. 您可以使用PyObject.__call__(Object... args)来调用任何可调用的Python对象。 You can get the PyFunction representing your function from the java side the same way you example is getting the python employee class. 您可以从java端获取表示函数的PyFunction,就像获取python employee类一样。

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. 另外,您可以通过在从Python解释器检索的函数上调用__tojava__(Interface.class)来隐藏java端的单个方法接口。 Detailed example (actually tested!): python file: 详细示例(实际测试!):python文件:

def tmp():
    return "some text"

java: 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

Importing only a method isn't possible because in Java, methods (or functions) aren't first-class objects, ie there's no way to refer to a method without first referring to some class (or interface). 不能仅导入方法,因为在Java中,方法(或函数)不是第一类对象,即没有首先引用某个类(或接口)就无法引用方法。 Even static methods are enclosed in a class and you refer to them via the class object. 甚至静态方法都包含在类中,您可以通过类对象引用它们。

However, you can get fairly close with the solution in introduced in Jython 2.5.2: Jython functions work directly as implementations of single abstract method Java interfaces (see http://www.zyasoft.com/pythoneering/2010/09/jython-2.5.2-beta-2-is-released/ ). 但是,您可以非常接近Jython 2.5.2中引入的解决方案:Jython函数直接作为单个抽象方法Java接口的实现工作(请参阅http://www.zyasoft.com/pythoneering/2010/09/jython- 2.5.2-beta-2-is-released / )。 So you can define an interface in Java - it's essential that it contains exactly one method definition: 所以你可以在Java中定义一个接口 - 它必须包含一个方法定义:

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

Plus something like this in Jython: 在Jython中加上这样的东西:

myFunction = lambda x, y : x * y

and use that as a MyInterface in Java. 并将其用作Java中的MyInterface You still have to use some sort of factory pattern, as described in the article you linked to, to get the Jython function to Java, but something like this works (probably contains errors, but the idea is): 您仍然必须使用某种工厂模式,如您链接的文章中所述,将Jython函数转换为Java,但是这样的工作(可能包含错误,但想法是):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM