我想知道是否有人尝试以某种方式调用 Jython 函数 来自 Clojure 内部,如果是的话,你是如何着手去做的。我有 没有使用过 Jython,但我想 Jython 解释器可以 以与任何其他 Java 代码和 Python 程序相同的方式调用 可以在其中运行。但是我想知道是否有可能 以某种方式从 Clojure 调用单个 python 函数。就像我说的,我 还没有尝试过,所以它实际上可能很简单 明显的。我只是想知道是否有人尝试过这样做。
谢谢, 罗布
最佳答案
注释:我刚刚意识到这个问题特别是关于从 Clojure 调用 Jython 函数,不是关于构建一个成熟的 Jython-Clojure 互操作解决方案...但!我已经就我对后者的初步想法写了一篇小文章,我想无论如何这是合乎逻辑的下一步。我的意思是,在没有相当方便地访问 Python 类的情况下,您如何使用有趣的 Python 包?编写 Python 函数来包装方法调用等是一个可能的想法……但是一个可怕的想法。所以不管怎样,还是去吧。
要从 Clojure 中基本调用 Jython 执行的 Python 函数,请阅读此处下方的第二段和代码片段。然后阅读其余部分以获得乐趣和意想不到的 yield 。
我认为最初的体验远非无缝......事实上,我的预测是消除颠簸确实是一种皇家痛苦。不过,我有一种预感,它实际上比从 Java 调用 Jython 更容易。我只是多头 0.02 欧元...希望更有知识的人来告诉我我不知道我在说什么。 ;-)
首先要注意的是,Jython 将一切 包装在它自己的类中,所有这些都派生自org.python.core.PyObject
。 , 懒得做 Python callables Callable
或 Runnable
等等。对于某些多方法/宏包装器,这实际上可能不是什么大问题。
Python 类可以从 Java 使用,但我(可能有缺陷)的理解是,通常情况下,当尝试对 Python 类的 Jython 实例进行操作时,Java 代码只会看到从 Java 基类或接口(interface)继承的方法。 .. 否则需要特殊格式的文档字符串(!)。这是 relevant page 的链接在 JythonWiki 上。 (不知道它有多新。)很酷的是,显然是 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
了。秒。我不知道如何传递关键字参数……尽管 Jython 以某种方式做到了这一点,所以一定有办法。
这是 ._jcall
的超基本助手-类型调用:
(defn py-call [pyf & args]
(apply (fn [pyf & args] (._jcall pyf (into-array args)))
(map #(if (string? %) (py-eval %) %)
(cons pyf args)))
您可以 .exec
包含 fact
的 Python 定义的字符串, 然后做 (py-call "fact" 10)
得到 #<PyInteger 5>
背部;如果您愿意,请打开包装。
等等……我不知道的是:
- 需要什么样的努力才能使它足够有用以将有趣的 Clojure 代码与有趣的 Python 代码连接起来。
- 如果为调用 Python 提供合理的语法,是否需要做任何对性能非常不利的事情。
关于python - Clojure Jython 互操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2129253/