2010-01-24 80 views
13

我想知道是否有人試圖以某種方式在Clojure中調用Jython函數 ,以及如果是這樣的話,你是怎麼做的。我有 未使用Jython,但我想象得到的Jython解釋器可以用與其他任何Java代碼相同的方式調用 ,並且Python程序 可以在其中運行。但是,我想知道是否有可能以某種方式調用Clojure中的各個python函數。就像我說的,我 還沒有嘗試過,所以它可能實際上很簡單,並且 顯而易見。我只是想知道是否有人嘗試過這樣做。Clojure Jython interop

感謝, 羅布

回答

13

的說明:我才意識到,這個問題是特別有關調用從Clojure的Jython的功能和關於建立全面Jython的Clojure的互操作解決方案。但!我已經寫了一篇關於後者的初步想法,我想這無論如何都是合乎邏輯的。我的意思是,你如何在沒有合理方便地訪問Python類的情況下使用有趣的Python包?編寫Python函數來包裝方法調用等是一個可能的想法......但相當可怕。無論如何,這裏就是這樣。

對於從Clojure基本調用Jython執行的Python函數,請閱讀下面第二段以及代碼片段。然後閱讀其餘的樂趣和意想不到的利潤。

我認爲這種體驗最初不會無縫......事實上,我的預測是平滑顛簸可能真的是皇室的痛苦。儘管如此,我還是覺得,從Java調用Jython實際上可能會更容易。從我這裏只花0.02歐元...可能有人更有知識,來告訴我,我不知道我在說什麼。 ;-)

要注意的第一件事是,Jython的包一切在自己的班級,全部來自org.python.core.PyObject派生,不打擾到使Python可調用CallableRunnable等,這實際上可能不會受到太大一些multimethod /宏包裝的問題。

Python類可以從Java中使用,但我(可能有缺陷)的理解是,通常情況下,試圖在Python類的Jython的製作情況下采取行動的時候,Java代碼只看到從Java基礎類或接口繼承的方法...否則需要特殊格式的文檔字符串(!)。這是JythonWiki上的relevant page的鏈接。 (不知道它是如何最新的。)很酷的是,顯然是一個PyObjectDerived(一個用戶定義的Python類的實例)可以確信用給定的參數調用它的方法。因此,通過包裝努力,人們可能希望能夠使用某種可以忍受的語法來做到這一點。

事實上,讓我們來看看一些代碼:

;; a handy instance of PythonInterpreter... 
(def python (org.python.util.PythonInterpreter.)) 
(.eval python "5") 
; -> #<PyInteger 5> 

好了,事情都包裹。一個有趣的Clojuresque解包:

(defmulti py-wrap class) 
;; but let's not wrap if already a PyObject... 
(defmethod py-wrap org.python.core.PyObject [pyo] pyo) 
(defmethod py-wrap Integer [n] (org.python.core.PyInteger n)) 
(defmethod py-wrap Long [n] (org.python.core.PyLong n)) 
(defmethod py-wrap BigInteger [n] (org.python.core.PyLong n)) 
(defmethod py-wrap String [s] (org.python.core.PyString s)) 

和對方上面:

(defmulti py-unwrap class) 
;; if unsure, hope it's not a PyObject at all... 
(defmethod py-unwrap :default [x] x) 
(defmethod py-unwrap org.python.core.PyInteger [n] (.getValue n)) 
(defmethod py-unwrap org.python.core.PyString [s] (.toString s)) 

的功能:您可以.__call__他們,你可以._jcall他們。後一個選項更令人愉快,因爲它接受普通Java對象的Java數組,儘管它仍然返回PyObject。前者採用適當數量的位置參數,應該已經按PyObject s。我不知道如何傳遞關鍵字參數......雖然Jython會以某種方式做到這一點,所以一定有辦法。

下面是._jcall超基本助手型呼叫:

(defn py-call [pyf & args] 
    (apply (fn [pyf & args] (._jcall pyf (into-array args))) 
     (map #(if (string? %) (py-eval %) %) 
       (cons pyf args))) 

您可以.execfact Python的定義,然後做(py-call "fact" 10)獲得#<PyInteger 5>背串;如果你覺得喜歡,就打開包裝。

等等等等......我不知道的是:

  1. 將需要什麼樣的努力,使這個足夠有用的接口與有趣的Python代碼有趣的Clojure代碼。
  2. 提供合理的Python調用語法需要做任何對性能不利的事情。
+2

謝謝,我一定會試試這個。我的目標是使用沒有Python限制的Natural Language Toolkit。對於lambda而言,Python的悲傷藉口並不是很有趣。 – rplevy 2010-01-25 16:28:10

+0

我在Clojure論壇上發表了一篇文章,Marc Downie指出Py.java2py和.__ tojava__將會很有用。 http://groups.google.com/group/clojure/browse_thread/thread/64827058a75af3ce – rplevy 2010-01-25 23:24:01

+0

剛剛注意!不過,很高興有鏈接。對於有Jython專家的建議也很好,也許有用的東西將會繼續討論...... :-)我很想知道如何使用NLT爲你提供幫助。我肯定會遵循Clojure小組的這個主題,並會很樂意在需要時嘗試和幫助。快樂黑客! – 2010-01-26 00:17:46