Clojure Jython互操作

rpl*_*evy 13 lisp python interop jython clojure

我想知道是否有人试图以某种方式从Clojure中调用Jython函数,以及如果是这样的话你是怎么做的.我没有使用过Jython,但我认为可以像调用任何其他java代码一样调用Jython解释器,并且可以在其中运行Python程序.但是我想知道是否有可能以某种方式调用Clojure中的各个python函数.就像我说的那样,我还没有尝试过,所以它实际上可能是直截了当的.我只是想知道是否有人试过这样做.

谢谢,罗布

Mic*_*zyk 13

注意:我刚刚意识到问题是关于从Clojure调用Jython函数而不是构建一个完整的Jython-Clojure互操作解决方案......但是!我已经对我对后者的初步想法做了一个小小的写作,我想这无论如何都是合乎逻辑的下一步.我的意思是,如果没有合理方便地访问Python类,你如何使用有趣的Python包呢?编写Python函数来包装方法调用等是一个可能的想法...而是一个可怕的想法.无论如何,这里也是如此.

对于从Clojure执行Jython执行的Python函数的基本调用,请阅读此点下面的第二段和代码片段.然后阅读其余的有趣和意想不到的利润.

我认为这种体验最初远非无缝......实际上,我的预测是平滑颠簸可能真的是一种皇室般的痛苦.尽管如此,我还是预感到从Java调用Jython实际上更容易.离我只有0.02欧元......可能会有更多知识渊博的人来告诉我,我不知道我在说什么.;-)

首先要注意的事情是,Jython的包装都在自己的班级,都来自衍生org.python.core.PyObject,不打扰到使Python可调用Callable或Runnable等,这实际上可能不会是太大的问题的一些多方法/宏包装.

可以从Java使用Python类,但我的(可能有缺陷的)理解是,通常,当尝试对Jython制作的Python类实例进行操作时,Java代码只能看到从Java基类或接口继承的方法...否则需要特殊格式的docstring(!).这是JythonWiki上相关页面的链接.(不知道它是如何最新的.)很酷的是,显然是PyObjectDerived(用户定义的Python类的一个实例)可以说服用给定的参数调用它的方法.因此,通过冗长的包装工作,人们可能希望能够使用有些可忍受的语法来完成它.

实际上,让我们看一些代码:

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

好吧,事情都被包裹了.一个有趣的Clojuresque unwrapper:

(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))
Run Code Online (Sandbox Code Playgroud)

与上述相对应:

(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))
Run Code Online (Sandbox Code Playgroud)

功能:你可以,.__call__他们可以._jcall.后一种选择有点令人愉悦,因为它接受常规Java对象的Java数组,尽管它仍然返回一个PyObject.前者采用适当数量的位置参数,这些参数应该已经是PyObjects.我不知道如何传递关键字参数......虽然Jython以某种方式做到了,所以必须有办法.

这是一个用于._jcall-type调用的超基本助手:

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

你可以.exec包含一个Python定义字符串fact,然后做(py-call "fact" 10)得到一个#<PyInteger 5>备用; 如果您愿意,请打开包装.

依此类推......我不知道的是:

  1. 需要做些什么样的努力才能使这个有用的Clojure代码与有趣的Python代码接口.
  2. 为Python调用提供合理的语法需要做一些非常糟糕的性能.

  • 谢谢,我肯定会尝试这个.我的目标是使用Natural Language Toolkit而不受Python的限制.Python对lambda的悲伤借口并不是很有趣. (2认同)