Як запустити скрипт 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.