Clojure Jython 互操作 [英] Clojure Jython interop

查看:38
本文介绍了Clojure Jython 互操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否有人尝试以某种方式调用 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.

谢谢,罗布

推荐答案

注意:我刚刚意识到问题是关于从 Clojure 调用 Jython 函数的,不是关于构建成熟的 Jython-Clojure 互操作解决方案......但是!我已经写了一篇关于我对后者的初步想法的小文章,我想无论如何这是合乎逻辑的下一步.我的意思是,在没有相当方便地访问 Python 类的情况下,您如何使用有趣的 Python 包?编写 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.

有关从 Clojure 中对 Jython 执行的 Python 函数的基本调用,请阅读此点下方的第二段和代码片段.然后阅读其余部分以获得乐趣和意想不到的利润.

我认为最初的体验远非无缝……事实上,我的预测是,抚平颠簸可能真的很痛苦.不过,我有一种预感,实际上从 Java 调用 Jython 会更容易.我只给了 0.02 欧元……希望有知识渊博的人来告诉我我不知道我在说什么.;-)

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. ;-)

首先要注意的是,Jython 将一切 包装在它自己的类中,所有这些类都源自 org.python.core.PyObject,并没有费心去制作 Pythoncallables CallableRunnable 等.对于某些多方法/宏包装器,这实际上可能不是太大的问题.

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 类可以从 Java 中使用,但我(可能有缺陷)的理解是,通常,当尝试对 Jython 制作的 Python 类实例进行操作时,Java 代码只能看到从 Java 基类或接口继承的方法... 否则需要特殊格式的文档字符串 (!).这是 JythonWiki 上相关页面的链接.(不知道它有多最新.)很酷的事情是,显然可以说服 PyObjectDerived(用户定义的 Python 类的实例)使用给定的参数调用其方法.因此,通过勤奋的包装工作,人们可能希望能够使用某种可以忍受的语法来做到这一点.

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.

其实我们看一些代码:

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

好了,东西都包好了.一个有趣的 Clojuresque 解包器:

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

和上面的对应物:

(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 以某种方式这样做,所以一定有办法.

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.

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

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

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

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. 需要付出什么样的努力才能使它足够有用,以便将有趣的 Clojure 代码与有趣的 Python 代码连接起来.
  2. 如果要为 Python 调用提供合理的语法,就必须做一些对性能非常不利的事情.

这篇关于Clojure Jython 互操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆