Jak uruchomić skrypt w języku Python z poziomu C #?

134

Tego rodzaju pytanie zadawano już wcześniej w różnym stopniu, ale wydaje mi się, że nie udzielono na nie zwięzłej odpowiedzi, więc zadaję je ponownie.

Chcę uruchomić skrypt w Pythonie. Powiedzmy, że to tak:

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

Który pobiera lokalizację pliku, czyta go, a następnie drukuje jego zawartość. Nie jest to takie skomplikowane.

Dobrze, więc jak mam to uruchomić w C #?

Oto, co mam teraz:

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

Kiedy podaję code.pylokalizację jako cmdi filenamelokalizację, ponieważ argsnie działa. Powiedziano mi, że powinienem przejść python.exejako cmd, a potem code.py filenamejako args.

Szukałem już od jakiegoś czasu i mogę znaleźć tylko osoby sugerujące użycie IronPythona lub czegoś podobnego. Ale musi istnieć sposób na wywołanie skryptu w Pythonie z C #.

Kilka wyjaśnień:

Muszę uruchomić go z C #, muszę przechwycić dane wyjściowe i nie mogę używać IronPython ani niczego innego. Niezależnie od tego, jaki hack masz, będzie dobrze.

PS: Rzeczywisty kod Pythona, który uruchamiam, jest znacznie bardziej złożony i zwraca dane wyjściowe, których potrzebuję w C #, a kod C # będzie stale wywoływał kod Pythona.

Udawaj, że to mój kod:

    private void get_vals()
    {
        for (int i = 0; i < 100; i++)
        {
            run_cmd("code.py", i);
        }
    }
Inbar Rose
źródło
1
Czy kod C # musi wywoływać skrypt Pythona, czy jest OK, jeśli (tak jak powiedziałeś na końcu) po prostu wywołujesz interpreter Pythona, który następnie uruchamia skrypt?
Gerald Versluis
1
Czy możesz używać IronPython?
Eugene
1
@GeraldVersluis jest w porządku, po prostu muszę być w stanie uruchomić go przez C # i przechwycić dane wyjściowe.
Inbar Rose

Odpowiedzi:

128

To nie działa, ponieważ masz UseShellExecute = false.

Jeśli nie używasz powłoki, będziesz musiał podać pełną ścieżkę do pliku wykonywalnego Pythona jako FileNamei zbudować Argumentsciąg, aby dostarczyć zarówno skrypt, jak i plik, który chcesz odczytać.

Pamiętaj też, że nie możesz, RedirectStandardOutputchyba że UseShellExecute = false.

Nie jestem do końca pewien, jak powinien być sformatowany łańcuch argumentów dla Pythona, ale będziesz potrzebować czegoś takiego:

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);
         }
     }
}
Mistrzowska moralność
źródło
Chcę mieć możliwość przeniesienia danych wyjściowych do mojego programu w celu późniejszego wykorzystania. więc muszę mieć Shellexecute jako fałszywe. mówisz, czy zdam c:\python26\python.exejako, cmda potem c:\temp\code.py c:\temp\testfile.txttak args, jak powinno działać?
Inbar Rose
Zaktualizowałem za pomocą szybkiego przykładu, napotkałem ten sam problem, gdy zrobiłem coś podobnego z węzłem
Master Morality
okej, teraz działa dla mnie. problem polega na tym, że musisz bardzo ostrożnie formatować łańcuchy. potrzebne "PATH"są jakieś ścieżki, nawet jeśli nie ma spacji ... dziwne ...
Inbar Rose
Mój działa bez podania pełnej ścieżki. Ustawiam się UseShellExecutedo falsei RedirectStandardOutputdo true.
Nikhil Girraj
1
Działa bez podawania ścieżki, jeśli instalator Pythona otrzymał polecenie dodania katalogu Pythona do zmiennej środowiskowej PATH (specyficznej dla systemu lub użytkownika).
Manfred
59

Jeśli chcesz używać IronPythona, możesz wykonywać skrypty bezpośrednio w C #:

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

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

Pobierz IronPython tutaj.

Chris Dunaway
źródło
3
wyjaśnij mi to, czy mogę to zrobić bez konieczności pobierania czegokolwiek? c # jest gotowy z tą wtyczką? także - czy mogę w tym uruchamiać zewnętrzne skrypty?
Inbar Rose
Musiałbyś zainstalować IronPython, który jest open source. Zaktualizowałem odpowiedź.
Chris Dunaway
8
zauważ, że IronPython i Python to nie to samo. Tak dla przypomnienia ...
Ron Klein,
1
Wydaje się, że IronPython nie obsługuje tego samego zestawu funkcji językowych, co Python 3.6.x. Dlatego IronPython jest opcją tylko wtedy, gdy nie używasz żadnej z tych funkcji języka. Jednak zdecydowanie warto spróbować.
Manfred
1
@RonKlein, nie są takie same, a jeśli próbujesz użyć biblioteki takiej jak scikit-learn (do celów ML), to też nie zadziała
moarra
28

Wykonaj skrypt Pythona z poziomu C

Utwórz projekt C # i napisz następujący kod.

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

print "Python C # Test"

Zobaczysz „Test języka Python C #” w konsoli C #.

Rohit Salunke
źródło
Mam plik skryptu Pythona w folderze systemu Windows, takim jak C:\Users\Documents\Visual Studio 2019. Ze względu na miejsce w ścieżce folderu jest traktowany jako separator argumentów, więc nie fileNamemożna go znaleźć. Czy jest sposób na ucieczkę z kosmosu?
Leon Chang
15

Napotkałem ten sam problem, a odpowiedź Mistrza Moralności nie zrobiła tego za mnie. Poniższe, oparte na poprzedniej odpowiedzi, zadziałały:

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

Na przykład, cmd byłoby, @C:/Python26/python.exea argumenty byłoby C://Python26//test.py 100, gdybyś chciał wykonać test.py z argumentem wiersza cmd 100. Zauważ, że ścieżka do pliku .py nie ma symbolu @.

Derek
źródło
2
Czy ktoś może skomentować, dlaczego jest to -1. Co jest z tym nie tak.
Keith Loughnane
2
Jest to dokładnie to samo, co odpowiedź powyżej, tylko przypisywanie nazwy pliku z parametru. Ale na końcu startma te same wartości
gniazdo
4

Tylko po to, aby zwrócić na to uwagę:

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

Działa świetnie.

cs0815
źródło
Hej, próbowałem tego i wygląda dobrze. Ale pojawia się błąd podczas importowania modułów. jak cv2. nie pisze żadnego modułu o nazwie cv2. Jak mogę to rozwiązać, czy masz jakiś pomysł
İsa GİRİŞKEN,
3
Ten link przekierowuje teraz do listy tematów. Tylko jeden wspomniał o Pythonie i nie jest to zbyt istotne.
Greg Vogel
IronPython3 nie jest gotowy do użycia: github.com/IronLanguages/ironpython3
James Hirschorn
3

Ustaw WorkingDirectory lub określ pełną ścieżkę skryptu w języku Python w argumencie

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
źródło
3

Właściwie jest to całkiem łatwe do integracji między Csharp (VS) i Pythonem z IronPythonem. To nie jest takie skomplikowane ... Jak powiedział już Chris Dunaway w sekcji odpowiedzi, zacząłem budować tę integrację dla mojego własnego projektu. N to całkiem proste. Po prostu wykonaj następujące kroki N, a otrzymasz wyniki.

Krok 1: Otwórz VS i utwórz nowy pusty projekt ConsoleApp.

krok 2: Przejdź do narzędzi -> Menedżer pakietów NuGet -> Konsola Menedżera pakietów.

krok 3: Po tym otwórz ten link w przeglądarce i skopiuj polecenie NuGet. Link: https://www.nuget.org/packages/IronPython/2.7.9

Krok 4: Po otwarciu powyższego linku skopiuj polecenie PM> Install-Package IronPython-Version 2.7.9 i wklej je w konsoli NuGet w VS. Zainstaluje pakiety pomocnicze.

krok 5: To jest mój kod, którego użyłem do uruchomienia pliku .py przechowywanego w moim katalogu 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
}
} 

krok 6: zapisz i wykonaj kod

Daulmalik
źródło
1
Jako programista nie wybieram rozwiązania, ponieważ jest „łatwe” do wdrożenia. Wybieram taki, który spełnia swoje zadanie. IronPython jest przeportowany tylko do Pythona 2.7 i prace nad Pythonem 3 trwają już od kilku lat i nie widać końca. Mam nadzieję, że Twój kod w Pythonie jest we właściwej wersji.
peter.cyc
od 27 kwietnia 2020 r .: github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.10 , ale nadal nie python 3.
Luuk
0

Mam problem z stdin/stout- gdy rozmiar ładunku przekracza kilka kilobajtów, zawiesza się. Muszę wywołać funkcje Pythona nie tylko z krótkimi argumentami, ale z niestandardowym ładunkiem, który może być duży.

Jakiś czas temu napisałem wirtualną bibliotekę aktorów, która pozwala na dystrybucję zadań na różne maszyny za pośrednictwem Redis. Aby wywołać kod Pythona, dodałem funkcję nasłuchiwania komunikatów z Pythona, przetwarzania ich i zwracania wyników z powrotem do .NET. Oto krótki opis tego, jak to działa .

Działa również na jednym komputerze, ale wymaga instancji Redis. Redis dodaje pewne gwarancje niezawodności - ładunek jest przechowywany do momentu przetworzenia potwierdzenia zakończenia. Jeśli przepracowany umiera, ładunek jest zwracany do kolejki zadań, a następnie jest ponownie przetwarzany przez innego pracownika.

VB
źródło
Dlaczego nie miałbyś po prostu używać plików przychodzących? zamiast obsługiwać całą tę pracę rury.
Inbar Rose
@InbarRose Miałem już system dla .NET, więc dodanie przetwarzania w Pythonie było bardzo łatwe i nadal mam dystrybucję i niezawodność - np. Mógłbym wysłać ładunek z komputera z systemem Windows i przetworzyć go z komputera z systemem Linux - pliki nie działałyby w tym walizka.
VB,
@InbarRose A kiedy ładunek jest naprawdę duży, mogę przekazać nazwę pliku na tej samej maszynie lub referencję S3 na AWS itp ...
VB