Come posso eseguire uno script Python da C #?


130

Questo tipo di domanda è stata posta in precedenza in varia misura, ma ritengo che non abbia ricevuto risposta in modo conciso e quindi lo chiedo di nuovo.

Voglio eseguire uno script in Python. Diciamo che è questo:

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

Che ottiene un percorso di file, lo legge, quindi stampa il suo contenuto. Non così complicato

Okay, quindi come posso eseguirlo in C #?

Questo è quello che ho ora:

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

Quando passo la code.pyposizione come cmde la filenameposizione in argsquanto non funziona. Mi è stato detto che avrei dovuto passare python.execome cmd, e poi code.py filenamecome args.

Sto cercando da un po 'di tempo e posso trovare solo persone che suggeriscono di usare IronPython o simili. Ma deve esserci un modo per chiamare uno script Python da C #.

Alcuni chiarimenti:

Devo eseguirlo da C #, devo catturare l'output e non posso usare IronPython o altro. Qualunque hack tu abbia, andrà bene.

PS: Il vero codice Python che sto eseguendo è molto più complesso di questo, e restituisce l'output di cui ho bisogno in C #, e il codice C # chiamerà costantemente il codice Python.

Fai finta che questo sia il mio codice:

    private void get_vals()
    {
        for (int i = 0; i < 100; i++)
        {
            run_cmd("code.py", i);
        }
    }

1
Il codice C # deve chiamare lo script Python o è OK se (come hai detto alla fine) chiami semplicemente l'interprete Python che quindi esegue lo script?
Gerald Versluis,

1
Ti è permesso usare IronPython?
Eugene,

1
@GeraldVersluis va bene, devo solo essere in grado di eseguirlo attraverso c # e catturare l'output.
Inbar Rose,

Risposte:


123

Il motivo per cui non funziona è perché hai UseShellExecute = false.

Se non usi la shell, dovrai fornire il percorso completo dell'eseguibile python come FileName, e costruire la Argumentsstringa per fornire sia il tuo script che il file che vuoi leggere.

Si noti inoltre che non è possibile a RedirectStandardOutputmeno che UseShellExecute = false.

Non sono sicuro di come formattare la stringa dell'argomento per Python, ma avrai bisogno di qualcosa del genere:

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

voglio essere in grado di portare l'output al mio programma da utilizzare in seguito. quindi devo avere shellexecute come falso. stai dicendo se passo c:\python26\python.execome cmde poi c:\temp\code.py c:\temp\testfile.txtcome argsdovrebbe funzionare?
Inbar Rose,

Ho aggiornato con un rapido esempio, ho riscontrato lo stesso problema quando ho fatto qualcosa di simile con il nodo
Master Morality

ok, ora funziona per me. il problema è che devi formattare le stringhe con molta attenzione. qualsiasi percorso è necessario "PATH"anche se non ci sono spazi ... strano ...
Inbar Rose

Il mio funziona senza fornire il percorso completo. Sto impostando UseShellExecutesu falsee RedirectStandardOutputsu true.
Nikhil Girraj,

1
Funziona senza fornire il percorso se al programma di installazione di Python è stato detto di aggiungere la directory Python alla variabile di ambiente PATH (specifica del sistema o dell'utente).
Manfred,

59

Se vuoi usare IronPython, puoi eseguire gli script direttamente in C #:

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

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

Ottieni IronPython qui.


3
spiegamelo, posso farlo senza dover scaricare nulla? c # è pronto con questo plugin? anche - posso eseguire script esterni con questo?
Inbar Rose,

Dovresti installare IronPython, che è open source. Ho aggiornato la risposta.
Chris Dunaway,

7
nota che IronPython e Python non sono esattamente la stessa cosa. Solo per la cronaca ...
Ron Klein,

1
IronPython non sembra supportare lo stesso set di funzionalità linguistiche di Python 3.6.x. Pertanto IronPython è un'opzione solo se non si utilizza nessuna di queste funzionalità linguistiche. Vale sicuramente la pena provare, però.
Manfred,

1
@RonKlein, non sono la stessa cosa, e se stai cercando di usare una libreria come scikit-learn (per scopi ML), non funzionerà neanche per te
moarra

28

Eseguire lo script Python da C

Crea un progetto C # e scrivi il seguente codice.

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

stampa "Python C # Test"

Vedrai il 'Test Python C #' nella console di C #.


Ho un file di script Python in una cartella di Windows come C:\Users\Documents\Visual Studio 2019. A causa dello spazio nel percorso della cartella, viene trattato come delimitatore args, quindi ho trovato il fileNamenon essere trovato. C'è un modo per sfuggire allo spazio?
Leon Chang,

15

Mi sono imbattuto nello stesso problema e la risposta del Maestro Morality non l'ha fatto per me. Di seguito, basato sulla risposta precedente, ha funzionato:

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

Ad esempio, cmd sarebbe @C:/Python26/python.exee args sarebbe C://Python26//test.py 100se si volesse eseguire test.py con l'argomento linea cmd 100. Notare che il percorso nel file .py non ha il simbolo @.


2
Qualcuno può commentare perché questo è -1. Che cosa c'è che non va.
Keith Loughnane,

2
È esattamente la stessa della risposta sopra solo l'assegnazione di FileName da un parametro. Ma alla fine startha gli stessi valori
annida il

4

Solo per attirare la tua attenzione su questo:

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

Funziona benissimo.


Ehi, l'ho provato e sembra funzionare bene. Ma sto ricevendo un errore nei moduli di importazione. come cv2. la sua scrittura non ha un modulo chiamato cv2. Come posso risolvere questo problema non hai idea
İsa GİRİŞKEN,

3
Questo collegamento ora reindirizza all'elenco di argomenti. Solo uno ha menzionato Python e non è molto rilevante.
Greg Vogel,

3

Impostare WorkingDirectory o specificare il percorso completo dello script python nell'argomento

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

3

In realtà è abbastanza facile fare l'integrazione tra Csharp (VS) e Python con IronPython. Non è molto complesso ... Come già detto da Chris Dunaway nella sezione delle risposte, ho iniziato a costruire questa integrazione per il mio progetto. N è piuttosto semplice. Segui questi passaggi N per ottenere i risultati.

passaggio 1: aprire VS e creare un nuovo progetto ConsoleApp vuoto.

passaggio 2: vai su strumenti -> Gestione pacchetti NuGet -> Console Gestione pacchetti.

passaggio 3: dopo questo aprire questo collegamento nel browser e copiare il comando NuGet. Link: https://www.nuget.org/packages/IronPython/2.7.9

passaggio 4: Dopo aver aperto il collegamento sopra riportato, copiare il comando PM> Installa-Pacchetto IronPython -Version 2.7.9 e incollarlo nella console NuGet in VS. Installerà i pacchetti di supporto.

passo 5: questo è il mio codice che ho usato per eseguire un file .py archiviato nella mia directory Python.exe.

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

passaggio 6: salvare ed eseguire il codice


Come sviluppatore non scelgo una soluzione perché è "facile" da implementare. Ne scelgo uno che fa il lavoro. IronPython è portato solo su Python 2.7 e il lavoro su Python 3 è in corso da un paio d'anni ormai, senza fine in vista. Spero che il tuo codice Python sia nella versione giusta.
peter.cyc,

dal 27 aprile 2020: github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.10 , ma non ancora pitone 3.
Luuk

0

Sto riscontrando problemi con stdin/stout: quando la dimensione del payload supera diversi kilobyte si blocca. Devo chiamare le funzioni di Python non solo con alcuni brevi argomenti, ma con un payload personalizzato che potrebbe essere grande.

Qualche tempo fa, ho scritto una libreria di attori virtuali che consente di distribuire compiti su macchine diverse tramite Redis. Per chiamare il codice Python, ho aggiunto funzionalità per ascoltare i messaggi da Python, elaborarli e restituire i risultati a .NET. Ecco una breve descrizione di come funziona .

Funziona anche su un singolo computer, ma richiede un'istanza Redis. Redis aggiunge alcune garanzie di affidabilità: il carico utile viene archiviato fino a quando un lavoro non riconosce il completamento. Se un lavoro muore, il payload viene restituito a una coda di lavoro e quindi rielaborato da un altro lavoratore.


Perché non dovresti usare solo i file in-out? invece di avere i tubi gestire tutto quel lavoro.
Inbar Rose,

@InbarRose Avevo già il sistema per .NET, quindi aggiungere l'elaborazione Python è stato molto semplice e ho ancora distribuzione e affidabilità - ad esempio, potrei pubblicare payload da un computer Windows ed elaborarlo da un computer Linux - i file non funzionerebbero in questo Astuccio.
VB,

@InbarRose E quando il payload è davvero grande, potrei passare un nome file sulla stessa macchina o riferimento S3 su AWS, ecc ...
VB
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.