如何从C#运行Python脚本?


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位置as cmdfilename位置as args无效时。有人告诉我,我应该通过python.execmd,然后code.py filename作为args

我已经寻找了一段时间,只能找到建议使用IronPython之类的人。但是必须有一种从C#调用Python脚本的方法。

一些澄清:

我需要从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解释器(然后运行该脚本)就可以了吗?
Gerald Versluis,2012年

1
您可以使用IronPython吗?
尤金(Eugene)2012年

1
@GeraldVersluis可以,我只需要能够通过c#运行它并捕获输出即可。
Inbar Rose

Answers:


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作为false。你说如果我通过c:\python26\python.execmd,然后c:\temp\code.py c:\temp\testfile.txtargs它应该工作?
Inbar Rose

我用一个简单的示例进行了更新,当我对节点执行类似操作时遇到了同样的问题
Master Morality'Aug

好吧,现在对我有效。问题是您需要非常仔细地格式化字符串。"PATH"即使没有空间也需要任何路径...奇怪的是
Inbar Rose

我的作品没有提供完整的路径。我设置UseShellExecutefalseRedirectStandardOutputtrue
Nikhil Girraj 2015年

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

从C执行Python脚本

创建一个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#测试”

您将在C#控制台中看到“ Python C#测试”


我在Windows文件夹(如)中有一个python脚本文件C:\Users\Documents\Visual Studio 2019。由于文件夹路径中的空间,它被视为args的定界符,因此我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行参数100执行test.py ,则cmd为,@C:/Python26/python.exe而args为C://Python26//test.py 100。请注意,.py文件的路径中没有@符号。


2
有人可以评论为什么是-1。它出什么问题了。
Keith Loughnane 2015年

2
它与上面的答案完全相同,只是您从参数分配FileName。但最后start具有相同的值
嵌套


3

设置WorkingDirectory或在Argument中指定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

实际上,使用IronPython在Csharp(VS)和Python之间进行集成非常容易。并没有那么复杂...正如克里斯·邓纳维(Chris Dunaway)在回答部分中所述,我开始为自己的项目建立这种整合。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命令并将其粘贴到VS的NuGet控制台中。它将安装支持包。

步骤5:这是我用来运行存储在我的Python.exe目录中的.py文件的代码。

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

如2020年4月27日的:github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.10,但仍然没有蟒蛇3
Luuk

0

我遇到问题stdin/stout-当有效负载大小超过几千字节时,它挂起了。我不仅需要使用一些简短的参数来调用Python函数,还需要使用可能很大的自定义有效负载。

前一段时间,我编写了一个虚拟角色库,该库允许通过Redis在不同计算机上分发任务。为了调用Python代码,我添加了侦听来自Python的消息,对其进行处理并将结果返回给.NET的功能。 这是它如何工作的简要说明

它也可以在一台机器上运行,但是需要一个Redis实例。Redis增加了一些可靠性保证-有效负载被存储,直到工作确认完成为止。如果工作人员死亡,则有效负载将返回到作业队列,然后由另一个工作人员重新处理。


您为什么不只使用输入输出文件?而不是让管道来处理所有这些工作。
Inbar Rose

@InbarRose我已经拥有用于.NET的系统,因此添加Python处理非常简单,并且我仍然具有分布和可靠性-例如,我可以从Windows计算机上发布有效负载并从Linux计算机上进行处理-文件在此不起作用案件。
VB

@InbarRose当有效载荷很大时,我可以在同一台计算机上传递文件名,或者在AWS上传递S3参考,等等……
VB
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.