Clojure Jython interop

Me preguntaba si alguien ha intentado de alguna manera llamar a las funciones de Jython desde Clojure, y cómo fue que hiciste esto si es así. No he usado Jython, pero me imagino que el intérprete de Jython se puede invocar de la misma manera que cualquier otro código Java, y los progtwigs de Python se pueden ejecutar dentro de él. Sin embargo, me pregunto si sería posible llamar a funciones Python individuales desde Clojure. Como dije, no he intentado esto todavía, por lo que podría ser sencillo y obvio. Me pregunto si alguien ha intentado hacer esto.

Gracias rob

Una nota: Me acabo de dar cuenta de que la pregunta es específicamente sobre cómo llamar a las funciones de Jython desde Clojure y no sobre cómo crear una solución de interoperabilidad Jython-Clojure completa … ¡Pero! Ya he producido una pequeña reseña de mis pensamientos iniciales sobre este último y creo que ese es el siguiente paso lógico de todos modos. Quiero decir, ¿cómo usaste los paquetes interesantes de Python sin un acceso razonablemente conveniente a las clases de Python? Escribir funciones de Python para envolver llamadas a métodos y similares es una idea posible … pero bastante horrible. Así que aquí va de todos modos.

Para las llamadas básicas de las funciones Python ejecutadas por Jython desde Clojure, lea el segundo párrafo debajo de este punto y los fragmentos de código. Luego lee el rest por diversión y ganancias inesperadas.

Creo que la experiencia inicialmente estaría lejos de ser perfecta … De hecho, mi predicción sería que allanar los baches podría ser realmente un dolor real. Sin embargo, tengo el presentimiento de que podría ser más fácil que llamar a Jython desde Java. Solo un longish € 0.02 de mi parte … Que alguien con más conocimientos venga y me muestre que no sé de qué estoy hablando. 😉

Lo primero que hay que notar es que Jython envuelve todo en sus propias clases, todas derivadas de org.python.core.PyObject , no se molesta en hacer Callable o Runnable etc. Esto podría no ser un gran problema para Algunos envoltorios multimetodo / macro.

Las clases de Python se pueden usar desde Java, pero mi entendimiento (posiblemente defectuoso) es que normalmente, cuando bash actuar sobre instancias de clases de Python hechas por Jython, el código Java solo ve los métodos heredados de una interfaz o clase base de Java … De lo contrario se requiere una cadena de documentos con formato especial (!). Aquí hay un enlace a la página correspondiente en JythonWiki. (No tengo idea de cuán actualizado está). Lo interesante es que, aparentemente, un PyObjectDerived (una instancia de una clase de Python definida por el usuario) puede ser convencido de llamar a sus métodos con los argumentos dados. Por lo tanto, con un esfuerzo de envoltura inteligente, uno podría esperar poder usar una syntax bastante soportable para hacerlo.

De hecho, vamos a ver algunos códigos:

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

Bueno, las cosas están envueltas. Un divertido envoltorio de clojuresco:

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

Y una contraparte de lo anterior:

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

Las funciones: Puedes .__call__ ellos y puedes ._jcall . La última opción es algo más agradable, ya que acepta una matriz de Java de objetos Java normales, aunque aún devuelve un PyObject . El primero toma un número apropiado de argumentos posicionales que ya deberían ser de PyObject s. No tengo idea de cómo pasar los argumentos de palabras clave … aunque Jython lo hace de alguna manera, por lo que debe haber una manera.

Aquí hay un ayudante ultra básico para ._jcall tipo ._jcall :

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

Puede .exec una cadena que contiene una definición de fact de Python, luego hacer (py-call "fact" 10) para obtener un # vuelta; desenvolver si te apetece

Y así sucesivamente … Lo que no sé es:

  1. ¿Qué tipo de esfuerzo sería necesario para que esto sea lo suficientemente útil como para interconectar el interesante código de Clojure con el interesante código de Python?
  2. Proporcionar una syntax razonable para las llamadas a Python requeriría hacer algo realmente malo para el rendimiento.