Як запустити скрипт Python із C #?


130

Таке запитання було задано раніше в різній мірі, але я вважаю, що на нього не було дано стислого відповіді, і тому я його знову задаю.

Я хочу запустити сценарій в 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
@GeraldVersluis все в порядку, мені просто потрібно мати змогу запустити його через c # і зловити результат.
Інбар Роза

Відповіді:


123

Причина, що вона не працює, полягає в тому, що у вас є 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це має працювати?
Інбар Роза

Я оновив швидкий приклад, я зіткнувся з тим же питанням, коли зробив щось подібне з вузлом
Master Morality

добре, це працює для мене зараз. проблема полягає в тому, що вам потрібно дуже обережно відформатувати рядки. будь-які шляхи потрібні, "PATH"навіть якщо немає пробілів ... дивно ...
Inbar Rose

Шахта працює без забезпечення повного шляху. Я налаштовую UseShellExecuteна falseі RedirectStandardOutputдо true.
Ніхіл Гіррай

1
Працює без надання шляху, якщо інсталятору Python було сказано додати каталог Python до змінної середовища PATH (специфічна для системи або користувача).
Манфред

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, який є відкритим кодом. Я оновив відповідь.
Кріс Дунавей

7
зауважте, що IronPython та Python - це не одне й те саме. Просто для запису ...
Рон Кляйн

1
Схоже, IronPython не підтримує той же набір мовних функцій, що й Python 3.6.x. Тому IronPython - це лише варіант, якщо ви не використовуєте жодну з цих мовних функцій. Це, безумовно, варто спробувати.
Манфред

1
@RonKlein, вони не однакові, і якщо ви намагаєтесь використовувати бібліотеку типу scikit-learn (для цілей ML), це також не підійде для вас
moarra

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 #"

Ви побачите "Тест Python C #" на консолі 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а аргументи будуть, 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

Це чудово працює.


Гей, я спробував це, і це виглядає добре. Але я отримую помилку при імпортних модулях. як cv2. його написання немає модуля з назвою cv2. Як я можу вирішити це, чи є у вас ідея
İsa GİRİŞKEN

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 Package Manager -> Console Package Manager.

крок 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: збереження та виконання коду


Як розробник я не вибираю рішення, оскільки це "легко" реалізувати. Я вибираю ту, яка виконує роботу. IronPython переноситься тільки на python 2.7, і робота над python 3 триває вже пару років, без кінця в поле зору. Сподіваємось, ваш код python знаходиться у правильній версії.
peter.cyc

станом на 27 квітня 2020 року: github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.10 , але все ще не python 3.
Luuk

0

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

Деякий час тому я написав віртуальну бібліотеку акторів, яка дозволяє поширювати завдання на різних машинах через Redis. Для виклику коду Python я додав функціональність для прослуховування повідомлень з Python, їх обробки та повернення результатів назад у .NET. Ось короткий опис того, як це працює .

Він працює і на одній машині, але вимагає екземпляр Redis. Redis додає деякі гарантії надійності - корисне навантаження зберігається до відпрацьованого підтвердження завершення. Якщо відпрацьований помирає, корисне навантаження повертається в чергу роботи, а потім переробляється іншим працівником.


Чому б ви просто не використовували вхідні файли? замість того, щоб труби обробляли всю цю роботу.
Inbar Rose

@InbarRose У мене вже була система для .NET, тому додати обробку Python було дуже просто, і я все ще маю розповсюдження та надійність - наприклад, я можу розміщувати корисну навантаження з машини Windows і обробляти її з машини Linux - файли не працюватимуть у цьому справа.
VB

@ InbarRose І коли корисна навантаження дійсно велика, я можу передати ім’я файлу на тій же машині або S3 посилання на AWS тощо ...
VB
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.