2009-01-13 6 views
10

J'ai un programme python, qui s'exécute sur l'implémentation de CPython, et à l'intérieur je dois appeler une fonction définie dans un programme java. Comment puis-je faire ceci?Comment appeler des objets et des fonctions java à partir de CPython?

Ce serait bien de pouvoir utiliser certains objets java aussi.

Jython n'est pas une option. Je dois lancer la partie python dans CPython.

Répondre

9

La meilleure chose à faire est

  1. Ecrire un CLI trivial pour votre java "fonction". (Il n'y a pas une telle chose, donc je suppose que vous voulez dire en fait une fonction de la méthode d'une classe Java.)

    public class ExposeAMethod { 
        public static void main(String args[]) { 
         TheClassToExpose x = new TheClassToExpose(); 
         x.theFunction(); 
        } 
    } 
    
  2. Compile et construire un fichier exécutable JAR avec ce que le point d'entrée. Appelez-le ExposeAMethod.jar

  3. Appelez ceci à partir d'une commande créée par sous-processus.

    import subprocess 
    p = subprocess.Popen("java -jar ExposeAMethod.jar", shell=True) 
    sts = os.waitpid(p.pid, 0) 
    

C'est le minimum. Et ce n'est vraiment pas beaucoup. Je compte 6 lignes de Java, 3 lignes de Python et vous êtes opérationnel.

Si vous souhaitez transmettre des arguments à cette fonction de constructeur ou de méthode de classe Java, vous devrez écrire quelques lignes de code supplémentaires. Vous avez deux choix.

  • Lisez les arguments de stdin, écrivez les résultats sur stdout. C'est relativement facile et fonctionne très bien.

  • Analyser les arguments en tant qu'options de ligne de commande vers Java, écrire les résultats sur stdout. C'est un peu plus difficile, mais cela se généralise très bien. Le bonus est que vous avez maintenant un programme Java en ligne de commande utile que vous pouvez réutiliser.

1

Je ne sais pas pour Python, la dernière fois que j'ai dû appeler java depuis l'application C (service NT), j'ai dû charger jvm.dll. Jetez un oeil à la documentation JNI. De plus, vous appelez toujours os.system ("java com.myapp.MyClass") si vous n'êtes pas concerné par les performances.

7

Si vous ne voulez pas écrire votre propre route JNI/C.

L'autre option est d'utiliser jpype qui est pour moi toujours ce que j'utilise pour accéder aux bases de données Oracle car l'installation des pilotes oracle c sur un PC est un pita. Vous pouvez faire des choses comme (de docs):

from jpype import * 
startJVM("d:/tools/j2sdk/jre/bin/client/jvm.dll", "-ea") # or path to your jvm 
java.lang.System.out.println("hello world") 
shutdownJVM() 

Il n'a pas été mis à jour en temps et il n'y a pas beaucoup de la manière de la documentation, mais il ne fonctionne raisonnablement bien.

+0

Les liens vont à une version désuète. Trouvez le bon ici: https://pypi.python.org/pypi/JPype1 https://github.com/originell/jpype et les documents ici: https://jpype.readthedocs.io/en/latest/ – bastian

13

Toutes mes excuses pour ressusciter le fil, mais je pense avoir une meilleure réponse :-)

Vous pouvez également utiliser Py4J qui comporte deux parties: une bibliothèque qui s'exécute dans CPython (ou n'importe quel interpréteur Python d'ailleurs) et une bibliothèque qui s'exécute sur la machine virtuelle Java que vous voulez appeler.

Il y a un exemple sur la frontpage et beaucoup de documentation, mais essentiellement, vous suffit d'appeler des méthodes Java à partir de votre code python comme si elles étaient des méthodes de python:

>>> from py4j.java_gateway import JavaGateway 
>>> gateway = JavaGateway()      # connect to the JVM 
>>> java_object = gateway.jvm.mypackage.MyClass() # invoke constructor 
>>> other_object = java_object.doThat() 
>>> other_object.doThis(1,'abc') 
>>> gateway.jvm.java.lang.System.out.println('Hello World!') # call a static method 

La communication se fait par des prises au lieu de JNI.

Disclaimer: Je suis l'auteur de Py4J

+0

Quels sont les avantages de l'utilisation des prises? N'est-ce pas plus lent que JNI? Avez-vous des statistiques de performance? – bastian

+1

JNI a moins de frais généraux à coup sûr! Les sockets sont plus portables (JNI n'est pas toujours amusant sur Windows) et supportent beaucoup plus de scénarios (par exemple, l'interpréteur Python sur une machine différente de la JVM). – Barthelemy

1

Regardez notre projet python-javabridge. C'est un wrapper Python autour du JNI, fortement utilisé par CellProfiler. Il offre à la fois un accès de bas niveau au JNI et un accès de haut niveau basé sur la réflexion aux objets Java.

+0

Comment python-javabridge se compare-t-il à [jpype] (https://pypi.python.org/pypi/JPype1)? Performance/stabilité? – bastian

Questions connexes