Wie führe ich ein Python-Skript von C # aus?

130

Diese Art von Frage wurde schon früher in unterschiedlichem Maße gestellt, aber ich habe das Gefühl, dass sie nicht präzise beantwortet wurde, und deshalb stelle ich sie erneut.

Ich möchte ein Skript in Python ausführen. Nehmen wir an, es ist das:

if __name__ == '__main__':
    with open(sys.argv[1], 'r') as f:
        s = f.read()
    print s

Wer bekommt einen Dateispeicherort, liest ihn und druckt dann seinen Inhalt. Nicht so kompliziert.

Okay, wie führe ich das in C # aus?

Das habe ich jetzt:

    private void run_cmd(string cmd, string args)
    {
        ProcessStartInfo start = new ProcessStartInfo();
        start.FileName = cmd;
        start.Arguments = args;
        start.UseShellExecute = false;
        start.RedirectStandardOutput = true;
        using (Process process = Process.Start(start))
        {
            using (StreamReader reader = process.StandardOutput)
            {
                string result = reader.ReadToEnd();
                Console.Write(result);
            }
        }
    }

Wenn ich den code.pyOrt als cmdund den filenameOrt übergebe args, funktioniert es nicht. Mir wurde gesagt, ich sollte python.exeals der cmdund dann code.py filenameals der passieren args.

Ich habe jetzt schon eine Weile gesucht und kann nur Leute finden, die vorschlagen, IronPython oder ähnliches zu verwenden. Es muss jedoch eine Möglichkeit geben, ein Python-Skript von C # aus aufzurufen.

Einige Klarstellungen:

Ich muss es von C # aus ausführen, ich muss die Ausgabe erfassen und ich kann IronPython oder irgendetwas anderes nicht verwenden. Welchen Hack du auch hast, es wird gut.

PS: Der tatsächliche Python-Code, den ich ausführe, ist viel komplexer als dieser und gibt die Ausgabe zurück, die ich in C # benötige, und der C # -Code ruft ständig den Python-Code auf.

Stellen Sie sich vor, dies ist mein Code:

    private void get_vals()
    {
        for (int i = 0; i < 100; i++)
        {
            run_cmd("code.py", i);
        }
    }
Inbar Rose
quelle
1
Muss der C # -Code das Python-Skript aufrufen oder ist es in Ordnung, wenn Sie (wie am Ende angegeben) nur den Python-Interpreter aufrufen, der dann das Skript ausführt?
Gerald Versluis
1
Dürfen Sie IronPython verwenden?
Eugene
1
@GeraldVersluis es ist okay, ich muss es nur durch c # laufen lassen und die Ausgabe abfangen können.
Inbar Rose

Antworten:

123

Der Grund, warum es nicht funktioniert, ist, dass Sie haben UseShellExecute = false.

Wenn Sie die Shell nicht verwenden, müssen Sie den vollständigen Pfad zur ausführbaren Python-Datei als angeben FileNameund die erstellenArguments Zeichenfolge , um sowohl Ihr Skript als auch die Datei bereitzustellen, die Sie lesen möchten.

Beachten Sie auch, dass Sie nicht können, es RedirectStandardOutputsei denn UseShellExecute = false.

Ich bin mir nicht ganz sicher, wie die Argumentzeichenfolge für Python formatiert werden soll, aber Sie benötigen ungefähr Folgendes:

private void run_cmd(string cmd, string args)
{
     ProcessStartInfo start = new ProcessStartInfo();
     start.FileName = "my/full/path/to/python.exe";
     start.Arguments = string.Format("{0} {1}", cmd, args);
     start.UseShellExecute = false;
     start.RedirectStandardOutput = true;
     using(Process process = Process.Start(start))
     {
         using(StreamReader reader = process.StandardOutput)
         {
             string result = reader.ReadToEnd();
             Console.Write(result);
         }
     }
}
Meister Moral
quelle
Ich möchte in der Lage sein, die Ausgabe in mein Programm zu übernehmen, um sie später zu verwenden. Also muss ich Shellexecute als falsch haben. Sie sagen, wenn ich c:\python26\python.exeals cmdund dann bestanden habe, c:\temp\code.py c:\temp\testfile.txtwie argses funktionieren sollte?
Inbar Rose
Ich habe mit einem kurzen Beispiel aktualisiert und bin auf dasselbe Problem gestoßen, als ich etwas Ähnliches mit Node gemacht habe
Master Morality
Okay, es funktioniert jetzt für mich. Das Problem ist, dass Sie die Zeichenfolgen sehr sorgfältig formatieren müssen. "PATH"
Inbar Rose
Meins funktioniert, ohne den vollständigen Pfad anzugeben. Ich setze UseShellExecuteauf falseund RedirectStandardOutputzu true.
Nikhil Girraj
1
Funktioniert ohne Angabe des Pfads, wenn das Python-Installationsprogramm angewiesen wurde, das Python-Verzeichnis zur Umgebungsvariablen PATH (system- oder benutzerspezifisch) hinzuzufügen.
Manfred
59

Wenn Sie bereit sind, IronPython zu verwenden, können Sie Skripte direkt in C # ausführen:

using IronPython.Hosting;
using Microsoft.Scripting.Hosting;

private static void doPython()
{
    ScriptEngine engine = Python.CreateEngine();
    engine.ExecuteFile(@"test.py");
}

Holen Sie sich IronPython hier.

Chris Dunaway
quelle
3
Erklären Sie mir das. Kann ich das tun, ohne etwas herunterladen zu müssen? c # kommt fertig mit diesem Plugin? auch - kann ich damit externe Skripte ausführen?
Inbar Rose
Sie müssten IronPython installieren, das Open Source ist. Ich habe die Antwort aktualisiert.
Chris Dunaway
7
Beachten Sie, dass IronPython und Python nicht genau dasselbe sind. Nur für die Aufzeichnung ...
Ron Klein
1
IronPython scheint nicht die gleichen Sprachfunktionen zu unterstützen wie Python 3.6.x. Daher ist IronPython nur eine Option, wenn Sie keine dieser Sprachfunktionen verwenden. Es ist auf jeden Fall einen Versuch wert.
Manfred
1
@ RonKlein, sie sind nicht gleich, und wenn Sie versuchen, eine Bibliothek wie scikit-learn (für ML-Zwecke) zu verwenden, funktioniert dies auch nicht für Sie
moarra
28

Führen Sie das Python-Skript von C aus

Erstellen Sie ein C # -Projekt und schreiben Sie den folgenden Code.

using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            run_cmd();
        }

        private void run_cmd()
        {

            string fileName = @"C:\sample_script.py";

            Process p = new Process();
            p.StartInfo = new ProcessStartInfo(@"C:\Python27\python.exe", fileName)
            {
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };
            p.Start();

            string output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();

            Console.WriteLine(output);

            Console.ReadLine();

        }
    }
}

Python sample_script

print "Python C # Test"

Sie sehen den 'Python C # -Test' in der Konsole von C #.

Rohit Salunke
quelle
Ich habe eine Python-Skriptdatei in einem Windows-Ordner wie C:\Users\Documents\Visual Studio 2019. Aufgrund des Leerzeichens im Ordnerpfad wird es als Trennzeichen für Argumente behandelt, sodass ich das fileNamenicht gefundene erhalten habe. Gibt es eine Möglichkeit, dem Raum zu entkommen?
Leon Chang
15

Ich hatte das gleiche Problem und die Antwort von Master Morality hat es nicht für mich getan. Folgendes, das auf der vorherigen Antwort basiert, hat funktioniert:

private void run_cmd(string cmd, string args)
{
 ProcessStartInfo start = new ProcessStartInfo();
 start.FileName = cmd;//cmd is full path to python.exe
 start.Arguments = args;//args is path to .py file and any cmd line args
 start.UseShellExecute = false;
 start.RedirectStandardOutput = true;
 using(Process process = Process.Start(start))
 {
     using(StreamReader reader = process.StandardOutput)
     {
         string result = reader.ReadToEnd();
         Console.Write(result);
     }
 }
}

Als Beispiel wäre cmd @C:/Python26/python.exeund args wäre, C://Python26//test.py 100wenn Sie test.py mit dem cmd-Zeilenargument 100 ausführen möchten. Beachten Sie, dass der Pfad in der .py-Datei nicht das @ -Symbol enthält.

Derek
quelle
2
Kann jemand kommentieren, warum dies -1 ist. Was stimmt damit nicht.
Keith Loughnane
2
Es ist genau das Gleiche wie die obige Antwort, nur dass Sie stattdessen FileName aus einem Parameter zuweisen. Aber am Ende starthat die gleichen Werte
Nest
4

Nur um Ihre Aufmerksamkeit darauf zu lenken:

https://code.msdn.microsoft.com/windowsdesktop/C-and-Python-interprocess-171378ee

Es funktioniert großartig.

cs0815
quelle
Hey, ich habe es versucht und es sieht gut aus. Aber ich bekomme Fehler beim Importieren von Modulen. wie als cv2. Es schreibt kein Modul namens cv2. Wie kann ich dieses Problem lösen zu tun haben u eine Idee
İsa GİRİŞKEN
3
Dieser Link leitet jetzt zur Themenliste weiter. Nur einer erwähnte Python und es ist nicht sehr relevant.
Greg Vogel
3

Legen Sie WorkingDirectory fest oder geben Sie den vollständigen Pfad des Python-Skripts im Argument an

ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "C:\\Python27\\python.exe";
//start.WorkingDirectory = @"D:\script";
start.Arguments = string.Format("D:\\script\\test.py -a {0} -b {1} ", "some param", "some other param");
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
    using (StreamReader reader = process.StandardOutput)
    {
        string result = reader.ReadToEnd();
        Console.Write(result);
    }
}
LIU YUE
quelle
3

Eigentlich ist es ziemlich einfach, die Integration zwischen Csharp (VS) und Python mit IronPython durchzuführen. Es ist nicht so komplex ... Wie Chris Dunaway bereits im Antwortbereich sagte, begann ich, diese Integration für mein eigenes Projekt zu erstellen. N es ist ziemlich einfach. Befolgen Sie einfach diese Schritte N Sie erhalten Ihre Ergebnisse.

Schritt 1: Öffnen Sie VS und erstellen Sie ein neues leeres ConsoleApp-Projekt.

Schritt 2: Gehen Sie zu Tools -> NuGet Package Manager -> Package Manager Console.

Schritt 3: Öffnen Sie anschließend diesen Link in Ihrem Browser und kopieren Sie den NuGet-Befehl. Link: https://www.nuget.org/packages/IronPython/2.7.9

Schritt 4: Kopieren Sie nach dem Öffnen des obigen Links den Befehl PM> Install-Package IronPython -Version 2.7.9 und fügen Sie ihn in NuGet Console in VS ein. Die unterstützenden Pakete werden installiert.

Schritt 5: Dies ist mein Code, mit dem ich eine in meinem Verzeichnis Python.exe gespeicherte .py-Datei ausgeführt habe.

using IronPython.Hosting;//for DLHE
using Microsoft.Scripting.Hosting;//provides scripting abilities comparable to batch files
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
class Hi
{
private static void Main(string []args)
{
Process process = new Process(); //to make a process call
ScriptEngine engine = Python.CreateEngine(); //For Engine to initiate the script
engine.ExecuteFile(@"C:\Users\daulmalik\AppData\Local\Programs\Python\Python37\p1.py");//Path of my .py file that I would like to see running in console after running my .cs file from VS.//process.StandardInput.Flush();
process.StandardInput.Close();//to close
process.WaitForExit();//to hold the process i.e. cmd screen as output
}
} 

Schritt 6: Speichern und Ausführen des Codes

Daulmalik
quelle
Als Entwickler wähle ich keine Lösung aus, weil sie "einfach" zu implementieren ist. Ich wähle einen aus, der den Job macht. IronPython wird nur auf Python 2.7 portiert und die Arbeit an Python 3 ist seit einigen Jahren auf Kurs, ohne dass ein Ende in Sicht ist. Hoffe, Ihr Python-Code ist in der richtigen Version.
peter.cyc
Stand 27. April 2020: github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.10 , aber immer noch nicht Python 3.
Luuk
0

Ich habe Probleme mit stdin/stout- wenn die Nutzlastgröße mehrere Kilobyte überschreitet, hängt sie. Ich muss Python-Funktionen nicht nur mit einigen kurzen Argumenten aufrufen, sondern auch mit einer benutzerdefinierten Nutzlast, die groß sein könnte.

Vor einiger Zeit habe ich eine virtuelle Akteursbibliothek geschrieben, mit der Aufgaben über Redis auf verschiedenen Computern verteilt werden können. Um Python-Code aufzurufen, habe ich Funktionen hinzugefügt, mit denen Sie auf Nachrichten aus Python warten, diese verarbeiten und die Ergebnisse an .NET zurückgeben können. Hier ist eine kurze Beschreibung, wie es funktioniert .

Es funktioniert auch auf einem einzelnen Computer, erfordert jedoch eine Redis-Instanz. Redis fügt einige Zuverlässigkeitsgarantien hinzu - Nutzdaten werden gespeichert, bis eine Arbeit den Abschluss bestätigt. Wenn eine Arbeit stirbt, wird die Nutzlast in eine Jobwarteschlange zurückgeführt und dann von einem anderen Arbeiter erneut verarbeitet.

VB
quelle
Warum würden Sie nicht einfach In-Out-Dateien verwenden? anstatt dass die Rohre all diese Arbeiten erledigen.
Inbar Rose
@InbarRose Ich hatte bereits das System für .NET, daher war das Hinzufügen der Python-Verarbeitung sehr einfach und ich habe immer noch Verteilung und Zuverlässigkeit - z. B. könnte ich Nutzdaten von einem Windows-Computer veröffentlichen und von einem Linux-Computer verarbeiten - Dateien würden hier nicht funktionieren Fall.
VB
@InbarRose Und wenn die Nutzlast wirklich groß ist, könnte ich einen Dateinamen auf demselben Computer oder eine S3-Referenz auf AWS usw. übergeben.
VB