Comment puis-je exécuter un script Python à partir de C#?
Ce genre de question a déjà été posée à des degrés divers, mais je pense qu'il n'a pas été répondu de manière concise et donc je le demande à nouveau.
Je veux exécuter un script en Python. Disons que c'est ceci:
if __name__ == '__main__':
f = open(sys.argv[1], 'r')
s = f.read()
f.close()
print s
Qui obtient un emplacement de fichier, le lit, puis imprime son contenu. Pas si compliqué.
OK, alors comment puis-je exécuter cela en C#?
C'est Ce que j'ai maintenant:
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);
}
}
}
Lorsque je passe l' code.py
emplacement cmd
et le filename
emplacement args
il ne fonctionne pas. On m'a dit que je devrais passer python.exe
comme cmd
, puis code.py filename
comme args
.
Je cherche depuis un moment maintenant et je ne peux trouver que des personnes suggérant d'utiliser IronPython ou autre. Mais il doit y avoir un moyen d'appeler un script Python à partir de C#.
Quelques éclaircissements:
Je dois l'exécuter à partir de C#, j'ai besoin de capturer la sortie, et je ne peux pas utiliser IronPython ou autre chose. Quel que soit le hack que vous avez sera bien.
P.S.: le code Python actuel que je cours est beaucoup plus complexe que cela, et il renvoie la sortie dont j'ai besoin en C#, et le code C# appellera constamment le Python.
Prétendre que c'est mon code:
private void get_vals()
{
for (int i = 0; i < 100; i++)
{
run_cmd("code.py", i);
}
}
6 réponses
La raison pour laquelle cela ne fonctionne pas est que vous avez UseShellExecute = false
.
Si vous n'utilisez pas le shell, vous devez fournir le chemin complet de l'exécutable python comme FileName
, et construire l' Arguments
chaîne d'approvisionnement à la fois votre script et le fichier que vous souhaitez lire.
Notez Aussi que vous ne pouvez pas RedirectStandardOutput
, sauf si UseShellExecute = false
.
Je ne suis pas tout à fait sûr de la façon dont la chaîne d'argument doit être formatée pour python, mais vous aurez besoin de quelque chose comme ceci:
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);
}
}
}
Si vous êtes prêt à utiliser IronPython, vous pouvez exécuter des scripts directement en C#:
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
private static void doPython()
{
ScriptEngine engine = Python.CreateEngine();
engine.ExecuteFile(@"test.py");
}
Exécuter le script Python à partir de C
Créez un projet C# et écrivez le code suivant.
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"
Vous verrez le 'Test Python C# ' dans la console de C#.
J'ai rencontré le même problème et la réponse de Master Morality ne l'a pas fait pour moi. Ce qui suit, qui est basé sur la réponse précédente, a fonctionné:
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);
}
}
}
Par exemple, cmd serait @C:/Python26/python.exe
et args serait C://Python26//test.py 100
Si vous vouliez exécuter test.py avec l'argument de ligne cmd 100. Notez que le chemin du fichier. py n'a pas le symbole@.
J'ai des problèmes avec stdin/stout
- lorsque la taille de la charge utile dépasse plusieurs kilo-octets, elle se bloque. J'ai besoin d'appeler des fonctions Python non seulement avec quelques arguments courts, mais avec une charge utile personnalisée qui pourrait être grande.
Il y a quelque temps, j'ai écrit une bibliothèque d'acteurs virtuels qui permet de distribuer des tâches sur différentes machines via Redis. Pour appeler le code Python, j'ai ajouté une fonctionnalité pour écouter les messages de Python, les traiter et renvoyer les résultats à .NET. Voici une brève description de la façon dont il fonctionne .
Cela fonctionne également sur une seule machine, mais nécessite une instance Redis. Redis ajoute des garanties de fiabilité-la charge utile est stockée jusqu'à ce qu'un travail reconnaisse l'achèvement. Si un worked meurt, la charge utile est renvoyée dans une file d'attente de travail, puis est retraitée par un autre worker.
Définissez WorkingDirectory ou spécifiez le chemin complet du script python dans L'Argument
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);
}
}