2012-05-10 15 views
12

Khi đọc và sử dụng this article, giả định rằng chúng tôi có định nghĩa đối tượng đầy đủ với các đối tượng lớp và ánh xạ (proxy) từ python đến java.Jython, chỉ sử dụng một phương thức từ Python từ Java?

Chỉ có thể nhập phương thức (không được định nghĩa bên trong lớp, nhưng sử dụng lớp python nội bộ) từ một đoạn mã trong python mà không gói nó trong định nghĩa lớp (không sử dụng mô hình nhà máy được mô tả ở trên).

Tôi muốn làm một số loại from myPyFile import myMethod từ java, và sau đó sử dụng myMethod, trực tiếp từ java (có thể là một phương thức tĩnh?)? Nhưng nếu điều này là có thể, tôi không tìm thấy bất kỳ đầu mối nào về cách thực hiện điều đó (các giao diện được mô tả trong bài viết có thể vẫn cần thiết để nói với Java cách sử dụng myMethod?)

Trân trọng.

EDIT: bây giờ tôi đối phó với Jython 2.5.2, vì vậy nó có thể là phiên bản phụ thuộc và dễ dàng hơn nhiều trong tương lai?

EDIT: Dưới in reply to Daniel:

Dưới đây là một mẫu mã, để tạo lại lỗi tôi nhận được, và cũng có thể có được một ví dụ làm việc kể từ trả lời hữu ích của bạn!

(Vâng và thêm một chút câu hỏi khác về việc lập bản đồ trở lại các đối tượng Java từ một năng suất -ed Python/Jython kết quả)

(@Joonas, Xin lỗi, tôi đã sửa đổi mã của tôi, và bây giờ tôi tôi không thể lùi lại đến lỗi mà tôi đã từng có)

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 phần: (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:

một phần trả lời bản thân mình, cho câu hỏi bên trong (bình luận bên trong):
(thực sự tôi cảm thấy câu trả lời và mã của tôi là xấu xí, nhưng nó hoạt động và có vẻ là ok để UN-tuple tôi làm không biết nếu có một Jythonic-cách tốt hơn để làm điều đó, nếu như vậy, tôi thực sự quan tâm :))

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:

Trả lời bản thân về phần "sản xuất a: " java.lang.ClassCastException: org.python.core.PySingleton không thể truyền sang MyInterface " ... hầu hết sự hiểu lầm và lỗi của tôi do thực tế là tôi đã quên để xử lý Java từ phần Python! (xem mã của tôi ở trên, tôi để nó không được giải thích về thực tế này bởi vì nó không phải là câu hỏi chính của tôi, và ở dạng thực tế của nó, đó là câu trả lời làm việc về câu hỏi chính này, cảm ơn Daniel và Joonas đã giúp tôi hiểu).Vì vậy, đối với mô hình nhà máy, ta nên KHÔNG quên thêm việc nhập khẩu đầy đủ đến file Python của nó:

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

class MyClass(MyInterface): 
    [...] 

Một khó khăn khác mà tôi đã có được để xử lý một cách chính xác việc nhập khẩu và các gói. BTW, thêm mã này vào mã trên sẽ tạo ra một TypeError : không thể chuyển đổi sang org.python.core.PyList nhưng đây là mối quan tâm khác ...

+0

Tôi không biết bất cứ cách nào tốt hơn để phần unpact của tuple trên java bên khác hơn là đúc để PyTuple. Cá nhân, tôi sẽ tạo ra một bên hàm python thứ hai để giải nén trên giá trị trả về của hàm thực. –

Trả lời

6

Bạn có thể sử dụng PyObject.__call__(Object... args) để gọi bất kỳ đối tượng Python có thể gọi. Bạn có thể nhận được các PyFunction đại diện cho chức năng của bạn từ phía java giống như cách bạn ví dụ là nhận được lớp nhân viên python.

Alternativeley, bạn có thể ẩn điều này sau một giao diện phương thức duy nhất ở phía java bằng cách gọi __tojava__(Interface.class) trên hàm bạn đã truy xuất từ ​​trình thông dịch Python. dụ chi tiết (thực sự thử nghiệm!): 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()); 

} 

đầu ra:

class org.python.core.PyFunction 
some text 
+0

tôi thực sự đang cố gắng theo cách này, nhưng bây giờ tôi nhận được một _ "java.lang.ClassCastException: org.python.core.PySingleton không thể chuyển sang MyInterfaceType "_ từ các số này: _PyObject myObj = jyMyClass .__ gọi __(); trả về (MyInterfaceType) myObj .__ tojava __ (MyInterfaceType.class); _ – user1340802

+0

Tôi ngạc nhiên, đối tượng bạn nhận được từ Jython nên là một PyFunction.Bạn có nhớ gửi mã Jython? –

+0

tôi đã thêm mã. – user1340802

2

Nhập khẩu chỉ là một phương pháp là không thể vì trong Java, các phương thức (hoặc các hàm) không phải là các đối tượng hạng nhất, nghĩa là không có cách nào để tham chiếu đến một phương thức mà không đề cập đến một số lớp (hoặc giao diện). Ngay cả các phương thức tĩnh được bao bọc trong một lớp và bạn tham khảo chúng thông qua đối tượng lớp.

Tuy nhiên, bạn có thể tương đối gần với giải pháp được giới thiệu trong Jython 2.5.2: Chức năng Jython hoạt động trực tiếp dưới dạng triển khai giao diện Java phương thức trừu tượng đơn lẻ (xem http://www.zyasoft.com/pythoneering/2010/09/jython-2.5.2-beta-2-is-released/). Vì vậy, bạn có thể định nghĩa một giao diện trong Java - đó là điều cần thiết mà nó chứa chính xác một phương pháp định nghĩa:

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

Thêm một cái gì đó như thế này trong Jython:

myFunction = lambda x, y : x * y 

và sử dụng như một MyInterface trong Java. Bạn vẫn phải sử dụng một số loại mẫu nhà máy, như được mô tả trong bài viết bạn đã liên kết, để có được hàm Jython cho Java, nhưng một số thứ như thế này hoạt động (có thể chứa lỗi, nhưng ý tưởng là):

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

cảm ơn bạn đã trả lời của bạn, BTW từ thử nghiệm đầu tiên của tôi tôi nhận được một _ "Không thể thực hiện một tham chiếu tĩnh đến phương thức không tĩnh myMethod (String, String, boolean) từ kiểu MyInterface" _, và tĩnh không được cho phép trong định nghĩa giao diện tôi không biết làm thế nào để tiến hành ... (mà không gói tất cả mọi thứ bên trong một lớp Python) – user1340802

+0

@ user1340802: Vâng, xin vui lòng gửi mã của bạn. Ví dụ của tôi không chứa 'myMethtod (String, String, boolean)' vì vậy tôi không biết bạn đang cố gắng làm gì. Lỗi này ngụ ý rằng bạn có thể đang cố gắng làm một cái gì đó như 'MyInterface.myMethod (...)' mà tất nhiên không hoạt động. –

+0

xin lỗi, tôi đã sửa đổi mã của tôi, và bây giờ tôi không thể quay trở lại lỗi mà tôi từng có. Nhưng đã thêm mã vào câu hỏi của tôi ... – user1340802

Các vấn đề liên quan