在C#程序里面调用python
in C#Python with 6 comments
Read:530

在C#程序里面调用python

in C#Python with 6 comments

我有个项目,需要去网站收集数据,用桌面软件去管理。网站收集数据用python最为合适,而window桌面软件可以用C#写。C#的桌面管理软件是主题,python的收集数据部分也必不可少,要是能把两种语言结合起来开发就好了。在C#里面触发某个事件,而调用python程序执行,哇,真是完美的计划,然而 现实给我两耳光,fuck。

使用IronPython包调用python

网上很多办法都是用IronPython包来实现C#调用python。
首先我们创建一个c#控制台程序
用的IDE是vs,在菜单栏找到工具——NuGet包管理器——管理解决方案的NuGet程序包
QQ截图20190223165013.png

然后搜索python,找到IronPython下载安装(Ps:我没有遇到过找不到的情况,不排除这种可能,毕竟什么都有可能。如果找不到应该是你vs的问题,怕不是什么垃圾破解版吧)
QQ截图20190223165147.png
IronPython安装完成后,会自动在项目里添加下面这些引用,其实在我这个例子里只需要 IronPython.dll 和 Microsoft.Scripting.dll 就可以了,其他的都不需要,可以删,但是没有必要,懒
QQ截图20190223165339.png
IronPython就安装好了,并不是安装了管一辈子,而是一个程序项目安装一次,就是说,你这次安装了,下次要写另一个程序需要调用python,那么还要安装一次在新的项目引用里

用C#IronPyhton调用python的代码

先看看我们需要使用的类型:

-ScriptEngine: 动态语言(IronPython)执行类,可于解析和执行动态语言代码。
-ScriptScope:构建一个执行上下文,其中保存了环境及全局变量;宿主(Host)可以通过创建不同的 ScriptScope 来提供多个数据隔离的执行上下文。
-ScriptSource:操控动态语言代码的类型,可以编译(Compile)、运行(Execute)代码。

a.py文件里面的内容

# -*- coding:utf-8 -*-
print ("这是我在a.py文件中打印的的内容,没有引用任何包")
print (str)

首先C#引入头文件

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

然后在C#主函数里面写

    try
    {
        ScriptEngine engine = Python.CreateEngine();
        ScriptScope scope = engine.CreateScope();
        //a.py文件放在C#程序的bin/Debug目录下的,当然你可以写.py绝对路径
        ScriptSource script = engine.CreateScriptSourceFromFile(@"a.py");
        string x = "这是C#里面声明的一个值";
        scope.SetVariable("str", x);//给pyhton传参,第一个实参为变量名,第二个为值
        var result = script.Execute(scope);
    }
    catch (Exception x)//捕捉异常
    {
        Console.WriteLine(x);//把异常打印出来
    }

最后可以得到.py文件的运行及结果
QQ截图20190223210531.png

调用python里面的函数

首先py文件里里面写一个函数

def main(x,y):
    return x+y

然后在c#主函数里面写

        ScriptEngine engine = Python.CreateEngine();
        dynamic py= engine.ExecuteFile(@"a.py");//读取脚本文件
        int dd = py.main(1,2);//调用脚本文件中对应的函数,传入参数
        Console.WriteLine(dd);//输出值

结果就出来了,1+2=3
QQ截图20190223185355.png

重点!IronPython的弊端

如果pyhton不使用第三方库,IronPython相当完美,但是使用第三方库的时候就各种问题来了,会报找不到模块xxx的错误,上网查证后发现此问题基本难以解决。有解决的办法,不能使用pip安装,pip安装没有.egg文件,必须引用.egg的文件才能使用(Ps:没试过.egg,我的包都是pip安装的。但是用.egg相当的麻烦,算了告辞)。如果你的py文件引用了第三方库,这个方法基本bug了,另寻办法。

C#调cmd执行pyhton

这个最实用了,既可以用文件流传参改数据,又可以兼容py调用的包,要求是运行的电脑上必须配有python环境

你需要一个思路,首先我们要运行桌面软件,然后调用py文件,py文件里面又引用了第三方库。如果用IronPython可以调用py文件,但是找不到包,就无法正常运行py文件。想想电脑上怎么能正常执行py文件。要么你用python的编译器运行,要么cmd运行,用python的编译器不太方便,所以我们就想到了用cmd运行python,只要你系统装了python的环境,安装了对应引用的包,cmd运行系统python是没有问题的。关于安装python环境看这里
QQ截图20190223215708.png

代码

首先我们需要给python传递参数,这里我们用文件流的形式,更改py文件里面的指定内容(这不就相当于改参数了吗)
需要给C#程序引入IO

using System.IO;

当我们要触发某个事件时调用pyhton,我们就在这个事件里面写上代码,先改参数,再运行

string[] lines = File.ReadAllLines(@"task.py");//打开相对路径的python程序,我把py文件放在C#的Debug目录下的。这里获得py文件的每一行信息,保存到数组里面,索引0就是第一行
            
//修改第xx行的数据,当然也可以是一个空的*.py,全部命令都修改进去,我这里举个例子
lines[33] = string.Format("for i in range({0},{1},1):", start.Text, end.Text);
lines[26] = string.Format("server = '{0}'", textBox6.Text);
lines[27] = string.Format("user = '{0}'", textBox7.Text);
lines[28] = string.Format("password = '{0}'", textBox8.Text);
//我读取了py文件的全部行,但是我只修改了一部分行,所以lines还是py的全部内容,只是改了一部分
File.WriteAllLines(@"task.py", lines, Encoding.UTF8);//创建一个新文件,并用指定编码在其写入制定的字符串数组,然后关闭该文件。路径和原来的py文件的路径一样就覆盖了

上面这一步就给py文件“传参”完成,其实就是重新写一遍需要参数的那一行,记得缩进不要写错了。
接下来就是调用cmd执行py文件了。切记系统python环境变量一定要搭建好。

 private void Result(string mingling)//传入cmd的命令
        {
            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;    //是否使用操作系统shell启动
            p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
            p.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
            p.StartInfo.RedirectStandardError = true;//重定向标准错误输出
            p.StartInfo.CreateNoWindow = true;//不显示程序窗口
            p.Start();//执行
            //向cmd窗口发送输入信息
            p.StandardInput.WriteLine(mingling);
        }
            

你只需要像Result函数传入一个cmd的运行命令就可以调用了。
在你需要触发调用的事件下面写上

 Result(@"python task.py");//需要执行的命令,电脑需要配置python环境

然后cmd就会执行python文件,不过你看不到,因为窗口被隐藏了,详情见Result函数
这个你的cmd python没执行完成之前,你退出了桌面应用程序,它还是会在后台执行,你打开资源管理器就知道了。自己注意就是了,在退出程序的时候尽量退出全部线程

打包python成exe文件,用C#调用exe

这个方法不需要python运行环境,但是你打包了python,就不能往里面传参了。而且好像运行速度比较慢。
思路就是把你的py文件打包成exe,自行Google,然后用C#执行这个exe文件。
暂时不写这个方法了,没时间去研究,也没啥必要。看后续写不写

如果对你有帮助,打钱

赞赏



Responses
  1. 现在留言框信息有了,刚才不行。。

    Reply
  2. python真火啊,身边学的人不少

    Reply
    1. @子午物联网

      哎,顺应时代。多一项技能多一口饭吃

      Reply
      1. @清秋

        是啊,都跟上时代才行

        Reply
  3. 打卡 学习

    Reply
  4. 虽然看不懂python,但能感觉到博主是搞技术的。

    Reply