Clojure Jython 互操作

发布于 2024-08-19 05:14:40 字数 248 浏览 2 评论 0原文

我想知道是否有人尝试过以某种方式调用 Jython 函数 从 Clojure 内部开始,以及如果是的话,您是如何做到这一点的。我有 没有使用过 Jython,但我想 Jython 解释器可以 以与任何其他 Java 代码和 Python 程序相同的方式调用 可以在其中运行。不过我想知道是否有可能 以某种方式从 Clojure 调用各个 python 函数。就像我说的,我 还没有尝试过,所以它实际上可能很简单 明显的。我只是想知道是否有人尝试过这样做。

谢谢, 抢

I was wondering if anyone has tried somehow calling Jython functions
from within Clojure, and how you went about doing this if so. I have
not used Jython, but I would imagine the Jython interpreter can be
invoked in the same way as any other java code, and Python programs
can be run within it. However I wonder if it would be possible to
somehow call individual python functions from Clojure. Like I said, I
have not tried this yet, so it might actually be straightforward and
obvious. I'm just wondering if anyone has tried doing this.

Thanks,
Rob

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

來不及說愛妳 2024-08-26 05:14:40

注意:我刚刚意识到这个问题具体是关于从 Clojure 调用 Jython 函数,而不是关于构建成熟的 Jython-Clojure 互操作解决方案......但是!我已经就我对后者的初步想法写了一篇小文章,我想无论如何这都是合乎逻辑的下一步。我的意思是,在没有相当方便地访问 Python 类的情况下,您如何使用有趣的 Python 包?编写 Python 函数来包装方法调用等是一个可能的想法……但这是一个可怕的想法。所以无论如何。

要了解从 Clojure 中 Jython 执行的 Python 函数的基本调用,请阅读这一点下面的第二段和代码片段。然后阅读其余部分以获得乐趣和意想不到的利润。

我认为这种体验最初远非无缝......事实上,我的预测是消除障碍可能真的是一种巨大的痛苦。不过,我有一种预感,它实际上比从 Java 调用 Jython 更容易。我只需支付 0.02 欧元...希望有更多知识渊博的人来告诉我我不知道我在说什么。 ;-)

首先要注意的是 Jython 将一切包装在它自己的类中,所有内容都派生自 org.python.core.PyObject,不费心去制作 Python callables Callable 或 Runnable 等。对于某些多方法/宏包装器来说,这实际上可能不是太大的问题。

Python 类可以从 Java 中使用,但我(可能有缺陷)的理解是,通常,当尝试对 Python 类的 Jython 生成的实例进行操作时,Java 代码只能看到从 Java 基类或接口继承的方法...否则需要特殊格式的文档字符串 (!)。以下是 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 定义的字符串,然后执行 < code>(py-call "fact" 10) 获取 # 返回;如果您愿意,请打开包装。

等等……我不知道的是:

  1. 需要付出什么样的努力才能使其足够有用,以将有趣的 Clojure 代码与有趣的 Python 代码连接起来。
  2. 为 Python 调用提供合理的语法需要做任何对性能非常不利的事情。

A note: I just realised that the question is specifically about calling Jython functions from Clojure and not about building a full-fledged Jython-Clojure interop solution... But! I've already produced a smallish write-up on my initial thoughts on the latter and I guess that's the logical next step anyway. I mean, how'd you go about using interesting Python packages without reasonably convenient access to Python classes? Writing Python functions to wrap method calls and the like is a possible idea... but rather a horrible one. So here goes anyway.

For basic calling of Jython-executed Python functions from Clojure read the second paragraph below this point and the code snippets. Then read the rest for fun and unanticipated profit.

I think that the experience would initially be far from seamless... In fact, my prediction would be that smoothing out the bumps could really be a royal pain. Still, I have a hunch it could actually be easier then calling into Jython from Java. Just a longish €0.02 from me... May someone more knowledgeable come and show me I don't know what I'm talking about. ;-)

The first thing to notice is that Jython wraps everything in its own classes, all deriving from org.python.core.PyObject, doesn't bother to make Python callables Callable or Runnable etc. This might actually not be too much of a problem with some multimethod / macro wrappers.

Python classes can be used from Java, but my (possibly flawed) understanding is that normally, when trying to act upon Jython-made instances of Python classes, Java code only sees the methods inherited from a Java base class or interface... Otherwise a specially formatted docstring (!) is required. Here's a link to the relevant page on the JythonWiki. (No idea how up-to-date it is.) The cool thing is, apparently a PyObjectDerived (an instance of a user-defined Python class) can be convinced to call its methods with the given arguments. So, with a dilligent wrapping effort, one might hope to be able to use somewhat bearable syntax to do it.

In fact, let's see some code:

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

Well, things are wrapped. A fun 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))

And a counterpart to the above:

(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))

The functions: You can .__call__ them and you can ._jcall them. The latter option is somewhat more pleasing, as it accepts a Java array of regular Java objects, although it still returns a PyObject. The former takes an appropriate number of positional arguments which should already by PyObjects. I've no idea how to pass in keyword arguments... though Jython does that somehow, so there must be a way.

Here's an ultra-basic helper for ._jcall-type calls:

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

You can .exec a string containing a Python definition of fact, then do (py-call "fact" 10) to get a #<PyInteger 5> back; unwrap if you feel like it.

And so on and so forth... What I don't know is:

  1. What kind of effort would be needed to make this useful enough to interface interesting Clojure code with interesting Python code.
  2. Would providing a reasonable syntax for calls into Python necessitate doing anything really bad for performance.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文