C#调用Python的最优方式
BIMCoder梁老师 BIMCoder梁老师 2020-07-03
原文链接
一、引言:
最近一直在用Tensorflow训练模型,经过普华永道数字方案组AI杨大师的细心指导与耐心帮助,总算把模型训练的比较靠谱了。由于Revit二次开发主要使用C#语言,如何在C#环境中调用Python脚本,并且得到Python运行结果成为了目前紧迫的问题。经过连续通宵的艰苦奋战和试错,接下来,我将告诉大家一个比较靠谱的方案及编程细节。
二、选择
1.如果在百度中搜索C#调用Python,大多数出现的结果是使用IronPython,但是目前的状况是IronPython对Python2的支持比较好,而目前许多Python代码都已经转成Python3,IronPython对Python3的兼容并没有达到完美。而我的Python脚本是Python3,所以在尝试性的使用IronPython并测试不顺后,果断放弃IronPython。
2.在Python中使用Tensorflow的情况,如果在百度中搜索C#调用python Tensorflow,大多数结果会安利你去使用TensorflowSharp,该库是专门用于使用C#语言搭建Tensorflow程序。但我负责任的告诉你,别上它们的当!Tensorflow在Python写作是最佳的,不要浪费时间花在转语言上面。
三、正文
那么如果我写了一段Tensorflow Python脚本,我该如何在C#环境中调用呢,Python脚本需要进行哪些改造才能让C#顺利的调用呢??请跟随梁老师的脚步!
1.C#的调用方式,注意点:
a.如果你需要传个矩阵给Python脚本,将你的矩阵保存成csv文件,让Python脚本去读这个文件,得到矩阵数据;
b.如果只传递普通的数字,字符串,那么直接通过arguments传递即可:
var result = string.Empty;
var pypath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "My.py");
var p = new ProcessStartInfo();
var sArguments = pypath;
sArguments += " "+param1+" "+ param2;
p.FileName = @"D:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\python.exe";
p.Arguments = sArguments;
p.UseShellExecute = false;
p.RedirectStandardError = true;
p.RedirectStandardOutput = true;
p.CreateNoWindow = true;
using (Process process = Process.Start(p))
{
using (StreamReader reader = process.StandardOutput)
{
string stderr = process.StandardError.ReadToEnd();
result = reader.ReadToEnd();
}
}
在上述例子中,我将两个参数param1与param2带入到名为My.py的Python脚本中,然后运行后的结果会返回到result中。
2.Python脚本的改造。如果Python脚本既需要得到C#传过来的csv文件,又需要接收单独的入参,同时输出结果给C#,那么可以这样编写:
# -*- coding:utf-8 -*-
#前面的我就不写了
if __name__ == "__main__":
dir = sys.argv[1]
path = os.path.join(dir,'Mydata.csv')
r = np.genfromtxt(open(path,"rb"),delimiter=",")[:,:-1]
final = int(sys.argv[2])
q_network = DeepNet(dir,r,final)
result = q_network.get(r,final)
print(result)
记住!结果一定要用print()出来,而且在Python脚本里不要有其他地方使用print(),不然会把所有print()内容都会发到C#的result里。有些可以结构化的数据可以先转成json字符串再让C#接收,在C#中使用Newtonsoft再把json编程结构化对象。