So rufen Sie eine Python-Funktion aus Node.js auf

Lesezeit: 8 Minuten

Benutzer-Avatar
Genjuro

Ich habe eine Express-Node.js-Anwendung, aber ich habe auch einen maschinellen Lernalgorithmus, den ich in Python verwenden kann. Gibt es eine Möglichkeit, Python-Funktionen aus meiner Node.js-Anwendung aufzurufen, um die Leistungsfähigkeit von Bibliotheken für maschinelles Lernen zu nutzen?

Benutzer-Avatar
theJoestJoeToEverJoe

Der einfachste Weg, den ich kenne, ist die Verwendung des Pakets “child_process”, das mit node.

Dann kannst du so etwas machen:

const spawn = require("child_process").spawn;
const pythonProcess = spawn('python',["path/to/script.py", arg1, arg2, ...]);

Dann müssen Sie sich nur noch vergewissern import sys in Ihrem Python-Skript, und dann können Sie darauf zugreifen arg1 verwenden sys.argv[1], arg2 verwenden sys.argv[2]usw.

Um Daten an den Knoten zurückzusenden, tun Sie einfach Folgendes im Python-Skript:

print(dataToSendBack)
sys.stdout.flush()

Und dann kann der Knoten auf Daten lauschen mit:

pythonProcess.stdout.on('data', (data) => {
 // Do something with the data returned from python script
});

Da dies die Übergabe mehrerer Argumente an ein Skript mit spawn ermöglicht, können Sie ein Python-Skript so umstrukturieren, dass eines der Argumente entscheidet, welche Funktion aufgerufen wird, und das andere Argument an diese Funktion übergeben wird usw.

Hoffe das war klar. Lassen Sie mich wissen, wenn etwas Klärungsbedarf hat.

  • @PauloS.Abreu: Das Problem habe ich mit exec ist, dass es einen Puffer anstelle eines Streams zurückgibt, und wenn Ihre Daten die überschreiten maxBuffer Einstellung, die standardmäßig auf 200 KB eingestellt ist, erhalten Sie eine Pufferüberschreitungs-Ausnahme und Ihr Prozess wird beendet. Seit spawn nutzt Streams, es ist flexibler als exec.

    – theJoestJoeToEverJoe

    13. Januar 2016 um 21:36 Uhr

  • Nur eine kleine Anmerkung, wenn Sie node verwenden, sollten Sie wahrscheinlich nicht das Schlüsselwort process verwenden

    – alexvicegrab

    28. Juli 2017 um 16:49 Uhr

  • Wie sollte ich externe Pip-Abhängigkeiten installieren? Ich brauche numpy für ein Projekt und kann es nicht ausführen, weil es nicht installiert ist.

    – javiergarval

    2. Januar 2019 um 11:43 Uhr

  • @javiergarval Das wäre besser als neue Frage statt als Kommentar geeignet.

    – theJoestJoeToEverJoe

    2. Januar 2019 um 17:31 Uhr

  • Gibt es eine andere Möglichkeit, Daten aus Python zurückzugeben, als durch Drucken? Mein Python-Skript gibt viele Protokolldaten aus und anscheinend hat es Probleme, all diese Daten zu leeren

    – lxknvlk

    10. Juni 2019 um 13:36 Uhr

Benutzer-Avatar
Amit Upadhyay

Beispiel für Personen mit Python-Hintergrund, die ihr maschinelles Lernmodell in die Node.js-Anwendung integrieren möchten:

Es verwendet die child_process Kern Modul:

const express = require('express')
const app = express()

app.get("https://stackoverflow.com/", (req, res) => {

    const { spawn } = require('child_process');
    const pyProg = spawn('python', ['./../pypy.py']);

    pyProg.stdout.on('data', function(data) {

        console.log(data.toString());
        res.write(data);
        res.end('end');
    });
})

app.listen(4000, () => console.log('Application listening on port 4000!'))

Es erfordert nicht sys -Modul in Ihrem Python-Skript.

Nachfolgend finden Sie eine modularere Methode zur Ausführung der Aufgabe mit Promise:

const express = require('express')
const app = express()

let runPy = new Promise(function(success, nosuccess) {

    const { spawn } = require('child_process');
    const pyprog = spawn('python', ['./../pypy.py']);

    pyprog.stdout.on('data', function(data) {

        success(data);
    });

    pyprog.stderr.on('data', (data) => {

        nosuccess(data);
    });
});

app.get("https://stackoverflow.com/", (req, res) => {

    res.write('welcome\n');

    runPy.then(function(fromRunpy) {
        console.log(fromRunpy.toString());
        res.end(fromRunpy);
    });
})

app.listen(4000, () => console.log('Application listening on port 4000!'))

  • Ich bin überrascht, dass dies nicht mehr Stimmen bekommen hat. Während die Antwort von @NeverForgetY2K in Ordnung ist, enthält diese Antwort ein detaillierteres Beispiel, einschließlich des Port-Listening, und verwendet die moderneren JS-Konventionen wie const & Promises.

    – Mike Williamson

    26. April 2018 um 23:18 Uhr

  • Tolles Beispiel. Promise One war gut, um einige Fehler zu erkennen, die ich im Python-Skript hatte.

    – htafoya

    14. Juni 2018 um 0:11 Uhr

  • Das war super einfach für mich zu Plug-and-Play und einfach zu debuggen, wie @htafoya erwähnte. Vielen Dank!

    – Alex L

    27. September 2020 um 17:07 Uhr


Benutzer-Avatar
Soumik Rakshit

Das python-shell Modul von extrabacon ist eine einfache Möglichkeit, Python-Skripte von Node.js aus mit einfacher, aber effizienter Kommunikation zwischen Prozessen und besserer Fehlerbehandlung auszuführen.

Installation:

Mit npm:
npm install python-shell.

Oder mit Garn:
yarn add python-shell

Ausführen eines einfachen Python-Skripts:

const PythonShell = require('python-shell').PythonShell;

PythonShell.run('my_script.py', null, function (err) {
  if (err) throw err;
  console.log('finished');
});

Ausführen eines Python-Skripts mit Argumenten und Optionen:

const PythonShell = require('python-shell').PythonShell;

var options = {
  mode: 'text',
  pythonPath: 'path/to/python',
  pythonOptions: ['-u'],
  scriptPath: 'path/to/my/scripts',
  args: ['value1', 'value2', 'value3']
};

PythonShell.run('my_script.py', options, function (err, results) {
  if (err) 
    throw err;
  // Results is an array consisting of messages collected during execution
  console.log('results: %j', results);
});

Die vollständige Dokumentation und den Quellcode finden Sie unter https://github.com/extrabacon/python-shell

  • Dieses Problem hindert mich daran, es zu verwenden – github.com/extrabacon/python-shell/issues/179

    – mhlavacka

    20. Februar 2019 um 23:56 Uhr

  • Wenn Sie diesen Fehler erhalten – TypeError: PythonShell.run is not a function Dann stellen Sie sicher, dass Sie es wie folgt importieren var {PythonShell} = require( ‘python-shell’);

    – Mohammed

    21. Dezember 2019 um 14:42 Uhr


Benutzer-Avatar
Georgy

Sie können jetzt RPC-Bibliotheken verwenden, die Python und Javascript unterstützen, wie z nullerpc

Von ihrer Titelseite:

Node.js-Client

var zerorpc = require("zerorpc");

var client = new zerorpc.Client();
client.connect("tcp://127.0.0.1:4242");

client.invoke("hello", "RPC", function(error, res, more) {
    console.log(res);
});

Python-Server

import zerorpc

class HelloRPC(object):
    def hello(self, name):
        return "Hello, %s" % name

s = zerorpc.Server(HelloRPC())
s.bind("tcp://0.0.0.0:4242")
s.run()

Die meisten vorherigen Antworten nennen den Erfolg des Versprechens in on (“data”), es ist nicht der richtige Weg, denn wenn Sie viele Daten erhalten, erhalten Sie nur den ersten Teil. Stattdessen müssen Sie es beim Endereignis tun.

const { spawn } = require('child_process');
const pythonDir = (__dirname + "/../pythonCode/"); // Path of python script folder
const python = pythonDir + "pythonEnv/bin/python"; // Path of the Python interpreter

/** remove warning that you don't care about */
function cleanWarning(error) {
    return error.replace(/Detector is not able to detect the language reliably.\n/g,"");
}

function callPython(scriptName, args) {
    return new Promise(function(success, reject) {
        const script = pythonDir + scriptName;
        const pyArgs = [script, JSON.stringify(args) ]
        const pyprog = spawn(python, pyArgs );
        let result = "";
        let resultError = "";
        pyprog.stdout.on('data', function(data) {
            result += data.toString();
        });

        pyprog.stderr.on('data', (data) => {
            resultError += cleanWarning(data.toString());
        });

        pyprog.stdout.on("end", function(){
            if(resultError == "") {
                success(JSON.parse(result));
            }else{
                console.error(`Python error, you can reproduce the error with: \n${python} ${script} ${pyArgs.join(" ")}`);
                const error = new Error(resultError);
                console.error(error);
                reject(resultError);
            }
        })
   });
}
module.exports.callPython = callPython;

Anruf:

const pythonCaller = require("../core/pythonCaller");
const result = await pythonCaller.callPython("preprocessorSentiment.py", {"thekeyYouwant": value});

Python:

try:
    argu = json.loads(sys.argv[1])
except:
    raise Exception("error while loading argument")

Benutzer-Avatar
Extrem

Viele der Beispiele sind Jahre veraltet und erfordern eine komplexe Einrichtung. Du kannst Geben JSPyBridge/pythonia einen Versuch (vollständige Offenlegung: Ich bin der Autor). Es ist Vanilla JS, mit dem Sie mit fremden Python-Objekten arbeiten können, als ob sie in JS vorhanden wären. Tatsächlich sorgt es für Interoperabilität, sodass Python-Code im Gegenzug JS über Callbacks und übergebene Funktionen aufrufen kann.

numpy + matplotlib-Beispiel mit dem ES6-Importsystem:

import { py, python } from 'pythonia'
const np = await python('numpy')
const plot = await python('matplotlib.pyplot')

// Fixing random state for reproducibility
await np.random.seed(19680801)
const [mu, sigma] = [100, 15]
// Inline expression evaluation for operator overloading
const x = await py`${mu} + ${sigma} * ${np.random.randn(10000)}`

// the histogram of the data
const [n, bins, patches] = await plot.hist$(x, 50, { density: true, facecolor: 'g', alpha: 0.75 })
console.log('Distribution', await n) // Always await for all Python access
await plot.show()
python.exit()

Durch CommonJS (ohne Wartezeit auf oberster Ebene):

const { py, python } = require('pythonia')
async function main() {
  const np = await python('numpy')
  const plot = await python('matplotlib.pyplot')
  ...
  // the rest of the code
}
main().then(() => python.exit()) // If you don't call this, the process won't quit by itself.

Ich bin auf Knoten 10 und Kindprozess 1.0.2. Die Daten von Python sind ein Byte-Array und müssen konvertiert werden. Nur ein weiteres kurzes Beispiel für eine HTTP-Anfrage in Python.

Knoten

const process = spawn("python", ["services/request.py", "https://www.google.com"])

return new Promise((resolve, reject) =>{
    process.stdout.on("data", data =>{
        resolve(data.toString()); // <------------ by default converts to utf-8
    })
    process.stderr.on("data", reject)
})

request.py

import urllib.request
import sys

def karl_morrison_is_a_pedant():   
    response = urllib.request.urlopen(sys.argv[1])
    html = response.read()
    print(html)
    sys.stdout.flush()

karl_morrison_is_a_pedant()

ps kein erfundenes Beispiel, da das http-Modul des Knotens einige Anforderungen, die ich stellen muss, nicht lädt

  • Ich habe ein Server-Backend, das auf nodejs aufgebaut ist, und ich habe einige auf maschinelles Lernen bezogene Python-Skripte, die ich mithilfe von untergeordneten Prozessen über nodejs spawne, wenn ich die Anfrage auf meinem nodejs-Server erhalte. Wie in diesem Thread vorgeschlagen. Meine Frage ist, ist dies der richtige Weg, oder kann ich mein Python-Skript wie einen Flaschendienst ausführen lassen, der mit zmq an einen Port gebunden ist, und ein Versprechen von nodejs an diesen Dienst ausführen. Mit Recht meine ich, wie ist die Speichereinsparung und die Geschwindigkeitseinsparungsmethode?

    – Aswin

    10. August 2018 um 12:28 Uhr


  • Sie möchten wahrscheinlich, dass das Python-Zeug unabhängig läuft. Sie möchten keine fest codierten Abhängigkeiten, insbesondere für etwas Komplizierteres wie einen ml-Dienst. Was wäre, wenn Sie dieser Architektur ein weiteres Stück hinzufügen wollten? Wie eine Caching-Schicht vor dem ml oder eine Möglichkeit, dem ml-Modell zusätzliche Parameter hinzuzufügen? Es ist Speicher, um auch einen Python-Server auszuführen, aber Sie werden wahrscheinlich die Flexibilität brauchen. Später können Sie die beiden Teile auf zwei Server aufteilen

    – 1 mike12

    10. August 2018 um 18:02 Uhr

  • Er fragte, ob er anrufen könne Funktiondas beantwortet die Frage nicht.

    – basiskarl

    27. September 2018 um 13:20 Uhr

  • @1mike12 “karl_morrison_is_a_pedant()” haha, ich liebe es, Kumpel!

    – basiskarl

    11. Oktober 2018 um 8:49 Uhr

1080460cookie-checkSo rufen Sie eine Python-Funktion aus Node.js auf

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy