Como executo um script Python a partir de c #?

130

Esse tipo de pergunta já foi feito em vários graus, mas acho que não foi respondido de maneira concisa e, portanto, pergunto novamente.

Eu quero executar um script em Python. Vamos dizer que é isso:

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

Que obtém um local para o arquivo, lê e depois imprime seu conteúdo. Não é tão complicado.

Ok, então como executo isso em c #?

Isto é o que eu tenho agora:

    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 o code.pylocal como cmde o filenamelocal como argsele não funciona. Foi-me dito que eu deveria passar python.execomo o cmd, e depois code.py filenamecomo o args.

Estou procurando há algum tempo e só consigo encontrar pessoas sugerindo o uso do IronPython ou algo assim. Mas deve haver uma maneira de chamar um script Python de C #.

Alguns esclarecimentos:

Preciso executá-lo em C #, preciso capturar a saída e não posso usar o IronPython ou qualquer outra coisa. Qualquer que seja o truque que você tenha, tudo ficará bem.

PS: O código Python atual que estou executando é muito mais complexo que isso, e retorna a saída que eu preciso em C #, e o código C # estará constantemente chamando o código Python.

Finja que este é o meu código:

    private void get_vals()
    {
        for (int i = 0; i < 100; i++)
        {
            run_cmd("code.py", i);
        }
    }
Inbar Rose
fonte
1
O código C # precisa chamar o script Python ou está tudo bem se (como você afirmou no final) você acabou de chamar o interpretador python que executa o script?
Gerald Versluis
1
Você tem permissão para usar o IronPython?
Eugene
1
@GeraldVersluis tudo bem, eu só preciso ser capaz de executá-lo através de c # e pegar a saída.
Inbar Rose

Respostas:

123

A razão pela qual não está funcionando é porque você tem UseShellExecute = false.

Se você não usar o shell, precisará fornecer o caminho completo para o executável python como FileNamee criar oArguments string para fornecer o script e o arquivo que deseja ler.

Observe também que você não pode, a RedirectStandardOutputmenos que UseShellExecute = false.

Não tenho muita certeza de como a sequência de argumentos deve ser formatada para python, mas você precisará de algo assim:

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);
         }
     }
}
Master Morality
fonte
Eu quero ser capaz de levar a saída para o meu programa para ser usado mais tarde. então eu preciso ter shellexecute como false. você está dizendo se eu passar c:\python26\python.execomo cmde, em seguida, c:\temp\code.py c:\temp\testfile.txtcomo argsdeve funcionar?
Inbar Rose
I atualizado com um exemplo rápido, eu corri para o mesmo problema quando eu fiz algo parecido com o nó
Moralidade Mestre
ok, funciona para mim agora. o problema é que você precisa formatar as strings com muito cuidado. todos os caminhos precisam "PATH"mesmo se não há espaços ... estranho ...
Inbar Rosa
A mina funciona sem fornecer o caminho completo. Estou definindo UseShellExecutepara falsee RedirectStandardOutputpara true.
Nikhil Girraj
1
Funciona sem fornecer o caminho se o instalador do Python foi solicitado a adicionar o diretório Python à variável de ambiente PATH (sistema ou usuário específico).
Manfred
59

Se você estiver disposto a usar o IronPython, poderá executar scripts diretamente em C #:

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

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

Obtenha o IronPython aqui.

Chris Dunaway
fonte
3
explique isso para mim, posso fazer isso sem precisar baixar nada? c # vem pronto com este plugin? também - posso executar scripts externos com isso?
Inbar Rose
Você precisaria instalar o IronPython, que é de código aberto. Eu atualizei a resposta.
precisa
7
observe que IronPython e Python não são exatamente a mesma coisa. Só para constar ...
Ron Klein
1
O IronPython parece não suportar o mesmo conjunto de recursos de linguagem que o Python 3.6.x. Portanto, o IronPython é apenas uma opção se você não usar nenhum desses recursos de linguagem. Definitivamente, vale a pena tentar.
Manfred
1
@ RonKlein, eles não são os mesmos, e se você estiver tentando usar uma biblioteca como o scikit-learn (para fins de ML), também não funcionará para você
moarra 28/01
28

Executar script Python de C

Crie um projeto C # e escreva o seguinte código.

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

        }
    }
}

Sample_script do Python

print "Teste Python C #"

Você verá o 'Python C # Test' no console do C #.

Rohit Salunke
fonte
Eu tenho um arquivo de script python em uma pasta do Windows como C:\Users\Documents\Visual Studio 2019. Por causa do espaço no caminho da pasta, ele é tratado como o delimitador de args, então obtive o fileNameque não pode ser encontrado. Existe uma maneira de escapar do espaço?
Leon Chang
15

Encontrei o mesmo problema e a resposta do Mestre Moralidade não fez isso por mim. O seguinte, baseado na resposta anterior, funcionou:

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

Como exemplo, cmd seria @C:/Python26/python.exee args seria C://Python26//test.py 100se você desejasse executar test.py com o argumento de linha cmd 100. Observe que o caminho do arquivo .py não possui o símbolo @.

Derek
fonte
2
Alguém pode comentar por que isso é -1. O que há de errado com isso.
precisa saber é o seguinte
2
É exatamente o mesmo que a resposta acima, apenas atribuindo FileName a partir de um parâmetro. Mas no final starttem os mesmos valores
aninhar
4

Apenas também para chamar sua atenção para isso:

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

Isso funciona muito bem.

cs0815
fonte
Ei, eu tentei isso e parece funcionar bem. Mas estou recebendo erro nos módulos de importação. como como CV2. sua escrita nenhum módulo chamado cv2. Como posso resolver este fazer u tem alguma idéia
İsa GİRİŞKEN
3
Este link agora redireciona para a lista de tópicos. Apenas um mencionou Python e não é muito relevante.
Greg Vogel
3

Defina WorkingDirectory ou especifique o caminho completo do script python no argumento

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
fonte
3

Na verdade, é muito fácil fazer a integração entre o Csharp (VS) e o Python com o IronPython. Não é tão complexo ... Como Chris Dunaway já disse na seção de respostas, comecei a criar essa integração para o meu próprio projeto. N é bem simples. Basta seguir estas etapas: você obterá seus resultados.

Etapa 1: Abra o VS e crie um novo projeto vazio do ConsoleApp.

Etapa 2: Vá para Ferramentas -> Gerenciador de Pacotes NuGet -> Console do Gerenciador de Pacotes.

Etapa 3: Depois disso, abra este link no seu navegador e copie o Comando NuGet. Link: https://www.nuget.org/packages/IronPython/2.7.9

etapa 4: Após abrir o link acima, copie o comando PM> Install-Package IronPython -Version 2.7.9 e cole-o no NuGet Console no VS. Ele instalará os pacotes de suporte.

Etapa 5: Este é o meu código que usei para executar um arquivo .py armazenado no meu diretório 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
}
} 

etapa 6: salve e execute o código

Daulmalik
fonte
Como desenvolvedor, não escolho uma solução porque é "fácil" de implementar. Eu escolho um que faz o trabalho. O IronPython é portado apenas para o python 2.7 e o trabalho no python 3 está em andamento há alguns anos, sem fim à vista. Espero que seu código python esteja na versão correta.
peter.cyc 12/02
em 27 de abril de 2020: github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.10 , mas ainda não é o python 3.
Luuk
0

Estou tendo problemas com stdin/stout- quando o tamanho da carga útil excede vários kilobytes, ele trava. Preciso chamar funções Python não apenas com alguns breves argumentos, mas com uma carga útil personalizada que pode ser grande.

Há um tempo atrás, escrevi uma biblioteca de atores virtuais que permite distribuir tarefas em diferentes máquinas via Redis. Para chamar o código Python, adicionei funcionalidade para escutar mensagens do Python, processá-las e retornar resultados ao .NET. Aqui está uma breve descrição de como funciona .

Também funciona em uma única máquina, mas requer uma instância Redis. O Redis adiciona algumas garantias de confiabilidade - a carga útil é armazenada até que um trabalho confirme a conclusão. Se um trabalhador morre, a carga útil é retornada para uma fila de trabalhos e, em seguida, é reprocessada por outro trabalhador.

VB
fonte
Por que você não usaria apenas arquivos de entrada e saída? em vez de fazer com que os canos lidem com todo esse trabalho.
Inbar Rose
@InbarRose Eu já tinha o sistema para .NET, portanto, a adição de processamento Python foi muito fácil e ainda tenho distribuição e confiabilidade - por exemplo, eu poderia postar carga útil de uma máquina Windows e processá-la em uma máquina Linux - os arquivos não funcionariam dessa maneira. caso.
VB
@InbarRose E quando carga é muito grande, eu poderia passar um nome de arquivo na mesma máquina ou referência S3 na AWS, etc ...
VB