¿Cómo ejecuto un script de Python desde C #?

130

Este tipo de preguntas se han hecho anteriormente en diversos grados, pero siento que no se ha respondido de manera concisa y, por lo tanto, vuelvo a preguntar.

Quiero ejecutar un script en Python. Digamos que es esto:

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

Que obtiene una ubicación de archivo, la lee y luego imprime su contenido. No tan complicado

Bien, entonces, ¿cómo ejecuto esto en C #?

Esto es lo que tengo ahora:

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

Cuando paso la code.pyubicación como cmdy la filenameubicación ya argsque no funciona. Me dijeron que debía pasar python.execomo el cmd, y luego code.py filenamecomo el args.

He estado buscando durante un tiempo y solo puedo encontrar personas que sugieran usar IronPython o algo así. Pero debe haber una manera de llamar a un script de Python desde C #.

Alguna aclaración:

Necesito ejecutarlo desde C #, necesito capturar la salida y no puedo usar IronPython ni nada más. Cualquier truco que tengas estará bien.

PD: El código de Python real que estoy ejecutando es mucho más complejo que esto, y devuelve el resultado que necesito en C #, y el código de C # llamará constantemente al código de Python.

Finge que este es mi código:

    private void get_vals()
    {
        for (int i = 0; i < 100; i++)
        {
            run_cmd("code.py", i);
        }
    }
Inbar Rose
fuente
1
¿El código C # tiene que llamar al script de Python o está bien si (como dijiste al final) simplemente llamas al intérprete de Python que luego ejecuta el script?
Gerald Versluis
1
¿Puedes usar IronPython?
Eugene
1
@GeraldVersluis está bien, solo necesito poder ejecutarlo a través de C # y capturar la salida.
Inbar Rose

Respuestas:

123

La razón por la que no funciona es porque tú sí UseShellExecute = false.

Si no usa el shell, tendrá que proporcionar la ruta completa al ejecutable de Python como FileName, y construir la Argumentscadena para proporcionar tanto su script como el archivo que desea leer.

También tenga en cuenta que no puede a RedirectStandardOutputmenos que UseShellExecute = false.

No estoy muy seguro de cómo se debe formatear la cadena de argumento para Python, pero necesitará algo como esto:

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);
         }
     }
}
Moralidad maestra
fuente
Quiero poder llevar la salida a mi programa para usarla más tarde. entonces necesito tener shellexecute como falso. estás diciendo si paso c:\python26\python.execomocmd y luego c:\temp\code.py c:\temp\testfile.txtcomo argsdebería funcionar?
Inbar Rose
Actualicé con un ejemplo rápido, me encontré con el mismo problema cuando hice algo similar con el nodo
Master Morality
Está bien, funciona para mí ahora. El problema es que necesita formatear las cadenas con mucho cuidado. cualquier camino necesita"PATH" incluso si no hay espacios ... extraño ...
Inbar Rose
La mía funciona sin proporcionar el camino completo. Me estoy poniendo UseShellExecuteafalse y RedirectStandardOutputpara true.
Nikhil Girraj
1
Funciona sin proporcionar la ruta si se le dijo al instalador de Python que agregue el directorio de Python a la variable de entorno PATH (sistema o usuario específico).
Manfred
59

Si está dispuesto a usar IronPython, puede ejecutar scripts directamente en C #:

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

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

Obtén IronPython aquí.

Chris Dunaway
fuente
3
explícame esto, ¿puedo hacer esto sin tener que descargar nada? ¿C # viene listo con este complemento? Además, ¿puedo ejecutar scripts externos con esto?
Inbar Rose
Tendría que instalar IronPython, que es de código abierto. He actualizado la respuesta.
Chris Dunaway
77
Tenga en cuenta que IronPython y Python no son exactamente lo mismo. Solo para que conste ...
Ron Klein
1
IronPython no parece admitir el mismo conjunto de características de lenguaje que Python 3.6.x. Por lo tanto, IronPython es solo una opción si no utiliza ninguna de esas funciones de idioma. Sin embargo, definitivamente vale la pena intentarlo.
Manfred
1
@RonKlein, no son lo mismo, y si estás tratando de usar una biblioteca como scikit-learn (para propósitos de ML), tampoco funcionará para ti
moarra
28

Ejecutar script Python desde C

Cree un proyecto C # y escriba el siguiente 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();

        }
    }
}

Python sample_script

imprimir "Prueba de Python C #"

Verá la 'Prueba de Python C #' en la consola de C #.

Rohit Salunke
fuente
Tengo un archivo de secuencia de comandos de Python en una carpeta de Windows como C:\Users\Documents\Visual Studio 2019. Debido al espacio en la ruta de la carpeta, se trata como delimitador de args, por lo que obtuve el fileNameno se puede encontrar. ¿Hay alguna forma de escapar del espacio?
Leon Chang
15

Me encontré con el mismo problema y la respuesta de Master Morality no lo hizo por mí. Lo siguiente, que se basa en la respuesta anterior, funcionó:

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 ejemplo, cmd sería @C:/Python26/python.exey args sería C://Python26//test.py 100si desea ejecutar test.py con el argumento de línea cmd 100. Tenga en cuenta que la ruta del archivo .py no tiene el símbolo @.

Derek
fuente
2
¿Alguien puede comentar por qué esto es -1? ¿Qué tiene de malo?
Keith Loughnane
2
Es exactamente lo mismo que la respuesta anterior, solo su nombre de archivo asignado de un parámetro. Pero al final starttiene los mismos valores
anida el
4

Solo para llamar su atención sobre esto:

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

Funciona muy bien

cs0815
fuente
Oye, he intentado esto y parece funcionar bien. Pero obtengo un error en los módulos de importación. como cv2. no está escribiendo ningún módulo llamado cv2. ¿Cómo puedo resolver esto? ¿Tienes alguna idea?
İsa GİRİŞKEN
3
Este enlace ahora redirige a la lista de temas. Solo uno mencionó Python y no es muy relevante.
Greg Vogel
3

Establezca WorkingDirectory o especifique la ruta completa de la secuencia de comandos de Python en el 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
fuente
3

En realidad, es bastante fácil hacer la integración entre Csharp (VS) y Python con IronPython. No es tan complejo ... Como Chris Dunaway ya dijo en la sección de respuestas, comencé a construir esta integración para mi propio proyecto. N es bastante simple. Simplemente siga estos pasos y obtendrá sus resultados.

Paso 1: Abra VS y cree un nuevo proyecto vacío de ConsoleApp.

Paso 2: Vaya a Herramientas -> Administrador de paquetes NuGet -> Consola Administrador de paquetes.

Paso 3: después de esto, abre este enlace en tu navegador y copia el comando NuGet. Enlace: https://www.nuget.org/packages/IronPython/2.7.9

Paso 4: Después de abrir el enlace anterior, copie el comando PM> Install-Package IronPython -Version 2.7.9 y péguelo en NuGet Console en VS. Instalará los paquetes de apoyo.

Paso 5: Este es mi código que he usado para ejecutar un archivo .py almacenado en mi directorio 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
}
} 

Paso 6: guarda y ejecuta el código

Daulmalik
fuente
Como desarrollador, no elijo una solución porque es "fácil" de implementar. Elijo uno que hace el trabajo. IronPython se transfiere solo a Python 2.7 y el trabajo en Python 3 está en curso durante un par de años, sin un final a la vista. Espero que su código de Python esté en la versión correcta.
peter.cyc
a partir del 27 de abril de 2020: github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.10 , pero aún no Python 3.
Luuk
0

Estoy teniendo problemas con stdin/stout : cuando el tamaño de la carga útil supera varios kilobytes, se cuelga. Necesito llamar a las funciones de Python no solo con algunos argumentos cortos, sino con una carga útil personalizada que podría ser grande.

Hace un tiempo, escribí una biblioteca virtual de actores que permite distribuir tareas en diferentes máquinas a través de Redis. Para llamar al código de Python, agregué funcionalidad para escuchar los mensajes de Python, procesarlos y devolver los resultados a .NET. Aquí hay una breve descripción de cómo funciona .

También funciona en una sola máquina, pero requiere una instancia de Redis. Redis agrega algunas garantías de confiabilidad: la carga útil se almacena hasta que un trabajo confirma la finalización. Si un trabajador muere, la carga útil se devuelve a una cola de trabajo y luego es reprocesada por otro trabajador.

VB
fuente
¿Por qué no usarías simplemente archivos de entrada? en lugar de hacer que las tuberías manejen todo ese trabajo.
Inbar Rose
@InbarRose Ya tenía el sistema para .NET, por lo que agregar el procesamiento de Python fue muy fácil y todavía tengo distribución y confiabilidad, por ejemplo, podría publicar la carga útil desde una máquina Windows y procesarla desde una máquina Linux, los archivos no funcionarían en este caso.
VB
@InbarRose Y cuando la carga útil es realmente grande, podría pasar un nombre de archivo en la misma máquina o una referencia S3 en AWS, etc ...
VB