之前了解过另外一种方法,把python程序打包成exe执行文件,太慢了,因为经过打包之后,c#在调用的时候,需要及其复杂的解包的过程。所以这里介绍一种方法,直接在c#里面调用python后台的方法。
首先我们一般调用python代码的时候要选择一个python解析器的路径,这里我么使用的是anaconda里面的python,因为里面带有很多第三方的包,不用我们再去找了,方便。下载完anaconda之后,在根目录下面会有一个python.exe和pythonw.exe,这里我们就用这个pythonw.相应的.py文件也要改成.pyw才能用pythonw运行。原因如下:
在这之前我们介绍一下python.exe和pythonw.exe的区别,python是命令行调用,就是我们一般cmd之后的小黑框框。如果我们单独的运行python程序的时候,黑框框的是理想的,它可以给出错误提示,但是我们在c# 程序里面调用,每次一调用python的时候就跳出来这么一个黑框框是很丑的,这就用到了pythonw,就是专门为界面化程序设计的一个运行程序。就直接在后台调用了程序,就不会又命令行的黑框框跳出来。缺点就是不会又报错信息。所以!!!!调试的时候用python,最后放到项目里面的时候用pythonw!
下面进入正题;首先我们需要在c#项目里添加一个ironpython 的引用。这个我参考了很多博主的博文,他们并没有介绍要添加,但是在我这里不添加的话,就调不成功。大致方法就是,我们在vs里右击引用,点击管理NuGet程序包,进入搜索界面,键入Ironpython,找到下载安装即可。部分操作截图如下:引用截图Nu Get程序包下载界面下面就是c#代码。这里我就随便写了一个按钮点击事件。具体的调用模块是这样的,我尽可能的注释,让大家看懂哦
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace py_c2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
//第一种方法string[] strArr = new string[5];//参数列表 string sArguments = @"Python\easy_main.pyw";//这里是python的文件名字 strArr[0] = "test";
strArr[1] = "wff";
//strArr[4] = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "python\\";//整个路径是 //strArr[2] = "2";//可以传输字符串 //strArr[3] = "new"; RunPythonScript(sArguments , strArr);
}
public static void RunPythonScript(string sArgName, params string[] tep)
{
Process p = new Process();
string path = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + sArgName;// 获得python文件的绝对路径(将文件放在c#的debug文件夹中可以这样操作) //path = @"C:\code_workspace\pyenose\" + sArgName;//如果没放debug下,可以直接写的绝对路径,替换掉上面的路径 //string path_python = path + "\\matlab"; p.StartInfo.FileName = @"C:\Anaconda3\pythonw.exe";//启动外部程序的类型,这里交代了Python的配置环境路径string sArguments = path;
sArguments = sArguments +" "+ tep[0]+" "+ tep[1];//实现参数的拼接+" " + tep[2]+ " " + tep[3] p.StartInfo.Arguments = sArguments;
p.StartInfo.UseShellExecute = false;是否使用操作系统shell启动,直接从可执行文件创建进程 p.StartInfo.RedirectStandardOutput = true;///由调用程序获取输出信息p.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息 p.StartInfo.RedirectStandardError = true;//重定向标准错误输出 p.StartInfo.CreateNoWindow = false;//不显示程序窗口 p.Start(); //实际上是新创建了一个进程 p.BeginOutputReadLine();
p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);//接受Python文件print的内容Console.ReadLine();
p.WaitForExit();
}
//下面是使用委托来输出打印信息static void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrEmpty(e.Data))
{
AppendText(e.Data + Environment.NewLine);
}
}
public delegate void AppendTextCallback(string text);
public static void AppendText(string text)
{
MessageBox.Show(text);
}
}
}
之后运行便可以调试成功了。
我的python文件是这样的,就是简答的两个字符串的拼接
import pandas
import argparse
if __name__=='__main__':
parser = argparse.ArgumentParser()
parser.add_argument("para1") ###加数
parser.add_argument("para2") ###加数
args = parser.parse_args()
arg1 = args.para1
path = args.para2
sum=arg1+path # 字符串的拼接
print(sum)
# print(result)
上面的c#代码已经尽量的把注释都写清楚了,包括定义python程序路径和调用函数的目录关系如图easy_mian.py在python目录下
end
20200701更新
注意!!!!调用文件的所有路径不要有空格!不要有空格!因为空格在命令行时衔接参数的,路径有空格就会混乱。文件夹用下划线替代空格不好么????
添加引用的时候,一定要注意Iron python有不同的版本,要看一下详细介绍,不同的版本兼容不同的目标框架(这里的Iron python2.7.10兼容4.5的目标框架)。
增强代码的可迁移性,可以做一个自己可以选择环境路径的功能。
迁移代码时,需要检查的几点:
1.代码中的文件名、算法文件中的文件类型、调用的python环境这三者要匹配(.py文件和.pyw文件、python.exe和pythonw.exe)
2.参数要匹配(包括拼接)
3.引用和c#的目标框架要匹配(Iron python和c#项目的目标框架)