Как запустить скрипт Python из C #?

131

Такого рода вопросы задавались раньше в разной степени, но я чувствую, что на него нет краткого ответа, поэтому я задаю его снова.

Я хочу запустить скрипт на Python. Скажем так:

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

Которая получает местоположение файла, читает его, а затем печатает его содержимое. Не все так сложно.

Итак, как мне запустить это на C #?

Вот что у меня есть сейчас:

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

Когда я передаю code.pyместо как cmdи filenameместо, как argsэто не работает. Мне сказали, что я должен пройти python.exeкак то cmd, а затем code.py filenameкак args.

Я давно искал и могу найти только людей, предлагающих использовать IronPython или что-то подобное. Но должен быть способ вызвать скрипт Python из C #.

Некоторые пояснения:

Мне нужно запустить его с C #, мне нужно записать вывод, и я не могу использовать IronPython или что-то еще. Какой бы хак у вас ни был, все будет в порядке.

PS: Фактический код Python, который я запускаю, намного сложнее, чем этот, и он возвращает результат, который мне нужен на C #, а код C # будет постоянно вызывать код Python.

Представьте, что это мой код:

    private void get_vals()
    {
        for (int i = 0; i < 100; i++)
        {
            run_cmd("code.py", i);
        }
    }
Инбар Роуз
источник
1
Должен ли код C # вызывать скрипт Python или все в порядке, если (как вы указали в конце) вы просто вызываете интерпретатор python, который затем запускает скрипт?
Джеральд Верслуис,
1
Разрешено ли вам использовать IronPython?
Евгений
1
@GeraldVerslu, все в порядке, мне просто нужно запустить его через C # и поймать вывод.
Inbar Rose

Ответы:

125

Причина, по которой он не работает, в том, что он у вас есть UseShellExecute = false.

Если вы не используете оболочку, вам придется указать полный путь к исполняемому файлу python как FileNameи построитьArguments строку для предоставления как вашего скрипта, так и файла, который вы хотите прочитать.

Также обратите внимание, что вы не можете, RedirectStandardOutputесли UseShellExecute = false.

Я не совсем уверен, как должна быть отформатирована строка аргумента для python, но вам понадобится что-то вроде этого:

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);
         }
     }
}
Мастер нравственности
источник
Я хочу иметь возможность переносить вывод в свою программу, чтобы использовать ее позже. поэтому мне нужно, чтобы shellexecute был ложным. вы говорите, если я прохожу, c:\python26\python.exeа cmdзатем c:\temp\code.py c:\temp\testfile.txtкак argsон должен работать?
Inbar Rose
Я обновился быстрым примером, я столкнулся с той же проблемой, когда сделал что-то подобное с узлом
Master Morality
хорошо, теперь у меня работает. проблема в том, что нужно очень тщательно форматировать строки. любые пути нужны, "PATH"даже если там нет пробелов ... странно ...
Инбар Роуз
Моя работает без указания полного пути. Я устанавливаю UseShellExecuteв falseи RedirectStandardOutputк true.
Nikhil Girraj
1
Работает без указания пути, если установщику Python было сказано добавить каталог Python в переменную среды PATH (системную или специфичную для пользователя).
Manfred
59

Если вы хотите использовать IronPython, вы можете выполнять скрипты прямо на C #:

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

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

Загрузите IronPython здесь.

Крис Данауэй
источник
3
объясните мне это, могу я сделать это, не скачивая ничего? c # готов с этим плагином? также - могу ли я запускать внешние скрипты с этим?
Inbar Rose
Вам нужно будет установить IronPython с открытым исходным кодом. Я обновил ответ.
Крис Данауэй,
8
обратите внимание, что IronPython и Python - это не совсем одно и то же. Просто для протокола ...
Рон Кляйн
1
IronPython, похоже, не поддерживает тот же набор языковых функций, что и Python 3.6.x. Поэтому IronPython - это вариант, только если вы не используете ни одну из этих языковых функций. Хотя попробовать определенно стоит.
Manfred
1
@RonKlein, это не одно и то же, и если вы пытаетесь использовать такую ​​библиотеку, как scikit-learn (для целей машинного обучения), это тоже не сработает для вас
Моарра
28

Выполнить скрипт Python из C

Создайте проект C # и напишите следующий код.

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

напечатать "Python C # Test"

Вы увидите «Python C # Test» в консоли C #.

Рохит Салунке
источник
У меня есть файл сценария Python в папке Windows, например C:\Users\Documents\Visual Studio 2019. Из-за пробела в пути к папке он рассматривается как разделитель аргументов, поэтому я понял, что fileNameневозможно найти. Есть ли способ сбежать из космоса?
Леон Чанг
15

Я столкнулся с той же проблемой, и ответ Мастера морали не помог мне. Следующее, основанное на предыдущем ответе, сработало:

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

Например, cmd будет, @C:/Python26/python.exeа args - C://Python26//test.py 100если вы хотите выполнить test.py с аргументом строки cmd 100. Обратите внимание, что путь к файлу .py не имеет символа @.

Дерек
источник
2
Может кто-нибудь прокомментировать, почему это -1. Что с этим не так.
Кейт Локнэйн,
2
Это точно так же, как и ответ выше, только вместо этого вы назначаете FileName из параметра. Но в конце startимеет те же значения
гнездо
4

Также обращаю на это ваше внимание:

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

Отлично работает.

cs0815
источник
Эй, я пробовал это, похоже, работает нормально. Но я получаю ошибку при импорте модулей. вроде как cv2. он не пишет модуль с именем cv2. Как я могу решить эту проблему, у тебя есть идеи?
Иса ГИРИКЕН
3
Эта ссылка теперь перенаправляет на список тем. Только один упомянул Python, и это не очень актуально.
Грег Фогель,
3

Задайте WorkingDirectory или укажите полный путь к скрипту python в аргументе

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

На самом деле довольно просто сделать интеграцию между Csharp (VS) и Python с IronPython. Это не так уж и сложно ... Как уже сказал Крис Данауэй в разделе ответов, я начал создавать эту интеграцию для своего собственного проекта. N это довольно просто. Просто выполните эти шаги N, и вы получите свои результаты.

Шаг 1: Откройте VS и создайте новый пустой проект ConsoleApp.

Шаг 2: перейдите в Инструменты -> Диспетчер пакетов NuGet -> Консоль диспетчера пакетов.

Шаг 3. После этого откройте эту ссылку в своем браузере и скопируйте команду NuGet. Ссылка: https://www.nuget.org/packages/IronPython/2.7.9

Шаг 4. После открытия указанной выше ссылки скопируйте команду PM> Install-Package IronPython -Version 2.7.9 и вставьте ее в консоль NuGet в VS. Он установит вспомогательные пакеты.

Шаг 5: Это мой код, который я использовал для запуска файла .py, хранящегося в моем каталоге 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
}
} 

Шаг 6: сохраните и выполните код

Daulmalik
источник
Как разработчик я не выбираю решение, потому что его «легко» реализовать. Я выбираю тот, который выполняет свою работу. IronPython портирован только на python 2.7, а работа над python 3 продолжается уже пару лет, и конца ей не видно. Надеюсь, ваш код Python находится в правильной версии.
peter.cyc
по состоянию на 27 апреля 2020 г .: github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.10 , но все еще не python 3.
Луук
0

У меня проблемы с stdin/stout- когда размер полезной нагрузки превышает несколько килобайт, он зависает. Мне нужно вызывать функции Python не только с короткими аргументами, но и с пользовательской полезной нагрузкой, которая может быть большой.

Некоторое время назад я написал библиотеку виртуальных акторов, которая позволяет распределять задачи на разные машины через Redis. Чтобы вызвать код Python, я добавил функции для прослушивания сообщений от Python, их обработки и возврата результатов обратно в .NET. Вот краткое описание того, как это работает .

Он также работает на одной машине, но требует наличия экземпляра Redis. Redis добавляет некоторые гарантии надежности - полезная нагрузка сохраняется до тех пор, пока работа не подтвердит завершение. Если обработанный умирает, полезная нагрузка возвращается в очередь заданий, а затем повторно обрабатывается другим исполнителем.

VB
источник
Почему бы вам просто не использовать файлы in-out? вместо того, чтобы всю эту работу выполнять трубы.
Inbar Rose
@InbarRose У меня уже была система для .NET, поэтому добавить обработку Python было очень легко, и у меня все еще есть распространение и надежность - например, я мог публиковать полезную нагрузку с машины Windows и обрабатывать ее с машины Linux - файлы не будут работать в этом кейс.
VB
@InbarRose И когда полезная нагрузка действительно велика, я мог бы передать имя файла на той же машине или ссылку S3 на AWS и т. Д.
В.Б.