聊聊c#与Python以及IronPython
简单说说这个意义。做了很久的c#,突然发现Python火了。就看看,估计这篇博文有点长,有点长,尽量包括主要的东西,还有点杂,浏览吧,选择自己喜欢的看看。
先看比较。网上一堆各种比较。但是主要比较语法。我感觉这个没有说的。Python语法就是简单,它的设计目的就是为了简洁。这个不管怎么比较都是Python简单。但是写了很久的c#,这样反而不习惯,因为c#有很多语法糖。其实c#最近都没有什么更新,后面再说这个。
再看性能,这个都说静态语言占据优势,具体我没有自己测试过。就不多说,大家有兴趣自己测试吧。
那么就是比起c#,java这些语言,Python的优势就是简洁小巧。先说到这里,后面再说。
接下来我们看看c#与Python的结合体IronPython。IronPython其实就是c#版本的Python的解释器,另外也有java版本的.这个玩意是微软支持的,但是作者是Python的原作者。
再来具体看看这个玩意的使用。可以在官网下载http://ironpython.net。也可以提供nuget直接加入。但是提醒大家的是这个玩意支持的Python3还不稳定,有的功能没有。
具体看看使用
1.代码中执行语句或者表达式
其实就是类似我们在Pyhon的交互下的输入。
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
string script = "print('Hello world!')";
var sourceCode = engine.CreateScriptSourceFromString(script);
var result = sourceCode.Execute<object>(scope);
Console.WriteLine(result);
看例子,主要就是调用的方法
engine.CreateScriptSourceFromString
实现语句或者表达式的执行。
再来,看看语句的参数传入
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
string script = "print('Hello %d' %number)";
scope.SetVariable("number", 123);
ScriptSource sourceCode = engine.CreateScriptSourceFromString(script);
var result = sourceCode.Execute<object>(scope);
Console.WriteLine(result);
看见没有,其实就是ScriptScope 这个东东,这个就是这一次的执行玩意,通过它传入参数的值。
因为这玩意是c#的解释器,所以有更加高级一点的东西支持。
定义一个c#类。
public class Foo
{
public string Name { get; set; }
public DateTime Birthday { get; set; }
public string DoSth()
{
return DateTime.Now.ToString();
}
}
再来一个例子
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
string script = @"print('Hello %s' %foo.Name)
foo.DoSth()";//注意这里换行是必须的
Foo foo = new Foo()
{
Name = "阿萨德",
Birthday = new DateTime(1999,2,2)
};
scope.SetVariable("foo", foo);
ScriptSource sourceCode = engine.CreateScriptSourceFromString(script);
var result = sourceCode.Execute<object>(scope);
Console.WriteLine(result);
你会发现执行是成功的。抛开Python。.NET平台本来就是支持动态语言执行的,这就是dynamic关键字为什么可以有,不清楚你可以再回过头看看dynamic。其实又回到.Net平台执行了。
这里表达式执行就说完了。
2.执行py文件
这个就是一般的Python的样子了,继续看例子。
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
string path = @"test.py";
Foo foo = new Foo()
{
Name = "阿萨德",
Birthday = new DateTime(1999,2,2)
};
scope.SetVariable("foo", foo);
ScriptSource sourceCode = engine.CreateScriptSourceFromFile(path);
var result = sourceCode.Execute<object>(scope);
Console.WriteLine(result);
把Doth方法移动到py文件,里面写入上面例子的表达式,可以看效果。
这样就介绍完了c#调用Python脚本了。
3.IronPython特性的混合编程
(1)函数调用
继续,例子走前面
ScriptRuntime pyRuntime = Python.CreateRuntime(); //创建一下运行环境
dynamic obj= pyRuntime.UseFile("debug.py");
int num1=3, num2=4;
int sum = obj.add(num1, num2); //调用Python文件中的求和函数
注意,上面的使用方法是c#直接调用py文件的add函数,这也是一种py文件的执行,但是它的使用已经和c#混在了一起。
(2)引入.NET库和对象
先看例子
from System import DateTime, String
formatStr = String.Format("{0} {1}", "Hello World! The current date and time is ", DateTime.Now)
print formatStr
print dir(String)
raw_input("press Enter to exit!")
这是一段Python代码,里面有使用.NET中的String和DateTime。这段代码可以使用前面的表达式方法或者py文件执行。这就直接使用了c#的东西。
再接着来一个,看例子
namespace CalcLib
{
public class Calc
{
public int Add(int a, int b)
{
return a + b;
}
public int Sub(int a, int b)
{
return a - b;
}
}
}
假如上面这个是开发的一个c#的CalcLib.dll,我现在需要按照Python来执行。
import clr
clr.AddReference('CalcLib')
#clr.AddReferenceToFile('CalcLib.dll')
from CalcLib import Calc
print dir(Calc)
calcObj = Calc()
print "result of 3+4 is:", calcObj.Add(3,4)
print "result of 10+2 is:", calcObj.Sub(10,2)
raw_input("press Enter to exit!")
这又是一段Python的代码了,就可以使用了。注意,这要求IronPython能够找到CalcLib.dll。把CalcLib.dll拷贝到项目的debug目录或者在在使用的IronPython时,添加路径,通过engine.SetSearchPaths设置。
好了,c#与Python的交互就聊到这里,更加复杂的就不说了。
3.接下来说说IronPython调用问题了
先贴段代码
//ScriptRuntime pyRuntime = Python.CreateRuntime(); //创建一下运行环境
//ScriptEngine engine = Python.CreateEngine();
//engine.CreateScriptSourceFromString("print('hello!')").Execute();
//Console.ReadLine();
ScriptRuntime pyRuntime = Python.CreateRuntime(); //创建一下运行环境
ScriptEngine engine = Python.CreateEngine();
engine.SetSearchPaths(new string[] { });//设置库的搜索
//ScriptScope obj = pyRuntime.UseFile("debug.py"); //调用一个Python文件
//obj.ImportModule("");
//engine.ImportModule("");
//pyRuntime.ExecuteFile("debug.py");
//ScriptScope runScope = pyRuntime.CreateScope();
ScriptScope engScope = engine.CreateScope();
dynamic obj= engine.ExecuteFile("debug.py",engScope);//开始调用解析(与Python文件调试过程一样)
obj= engine.CreateScriptSourceFromFile("debug.py", Encoding.UTF8);
int num1=3, num2=4;
int sum = obj.add(num1, num2); //调用Python文件中的求和函数
//Console.Write("Sum:");
看见没有,那一堆的调用方法,其实实现是一样的,这就是Python的设计思想和c#的不同。Python是一个方法解决一件事情,即使它不是那么优雅,也不会扩展成多个方法,而c#则是提供多个方法解决一件事情,看起来灵活,满足各种参数传递。
其实这里的真实的顺序ScriptRuntime,ScriptEngine,ScriptScope,ScriptSource。具体是什么大家自己搜索。
我们调用时,无非是IronPython自动在后面默认创建了。比如直接用ScriptEngine执行py文件,则ScriptRuntime默认创建了,反过来用ScriptRuntime执行,也是默认创建了一个ScriptEngine,还是调用了ScriptEngine。按照c#一般的使用方式所以给了下面的代码。
ScriptEngine engine = Python.CreateEngine();
//添加搜索路径
var path=engine.GetSearchPaths();
List<string> lst = new List<string>(path.Count);
lst.AddRange(path);
lst.Add("debug");
engine.SetSearchPaths(lst.ToArray());
//
engine.ImportModule("");//标准模板
engine.ExecuteFile("debug.py");
engine.Execute("print('hell0')");
// ScriptSource scriptSource=
//engine.CreateScriptSourceFromFile("debug.py");//这里有一个编译过程
// scriptSource.Execute();
//如果有方法调用。
dynamic rpython = engine.ExecuteFile("debug.py");
rpython.Add(3, 4);
这大概就是大家常见的过程了。另外我注释的部分编译过程,在引擎调用ExecuteFile方法时内部就默认创建调用了该过程。前面已经介绍了几个类的执行过程。
4.解决问题了
模块搜索
(1)
ScriptEngine engine = Python.CreateEngine();
engine.ImportModule("");//标准模板
(2)
//添加搜索路径
var path=engine.GetSearchPaths();
List<string> lst = new List<string>(path.Count);
lst.AddRange(path);
lst.Add("debug");
engine.SetSearchPaths(lst.ToArray());
(3)
var options = new Dictionary<string, object>();
options["Frames"] = true;
options["FullFrames"] = true;
ScriptEngine engine = Python.CreateEngine(options);
最好的解决方法,项目定住库的位置,然后在调用的py文件里面加入以下代码:
import re,sys
sys.path.append("C:\Users\Administrator\Desktop\python\ironPython\WebApplication1\Lib") //这是本地调式用库
sys.path.append("C:\ironPython\Lib")
直接把Python的问题放在Python中解决。
编辑器问题
编辑器所在主线程模式只能使用STA线程,这也是vs默认的。
这也就差不多了,最后说说vs2017开发.
在vs2017中可以开发Python.需要在vs安装选择Python.这样其实配置vs2017的一些环境(可以选择安装Python3.6,这是vs2017集成安装的版本)。会在项目创建中添加Python项。
另外值得注意的是,一些博文说VS安装的Python是建立在vs安装目录下,但是我当前机器已经安装了官网Python环境,所以vs创建Python默认环境就是我已经安装好的官网Python环境,但是发现可以右键Python环境进行修改添加。vs2017可以执行,但是没有编辑提示,需要安装插件python for visual studio。
值得一说的vs2017的Python项目创建里面是2类,一类是Python应用程序,一类是IronPython应用程序,看清楚了。都是需要环境的。
好了,回到正题了,说说c#与Python了。
一直以来形成了java占据web,c#占据桌面系统开发。这是和各自的生态环境相关的,由于.NET长期闭源,被java抢占了市场,java有很多开源组件。Python由于自己的特点,占据了数据分析,人工智能方面。所以是根据各自优势来的。
所以完整的比较是没有意义的。另外由于.NET这种大平台(还有java)是由有关企业占用主导,所以只会关注最基础的实现和提供库,不像Python是由社区来引导支持的,这就造成了一种局面。Python在某一方有开源的库支持,最后变成了标准,然后又以模块的方式提供。但是c#就不会,只会提供最基础的,然后专注技术优化,性能优化,新技术创新。这样就决定了市场环境。那么Python就多了一个优势,在某一方面有标准库(优秀的第三方库)来支持,而c#不会有,从定位和开发驱动就决定了。例如,c#就不可能专门提供数据分析类似Python的pandas,只会提供一般的数据处理类(例如文件读取,包括json处理都是第三方的),这就是c#的定位,否则会很臃肿。
接着说说c#,.NET,vs2017.简单说几句废话,c#是开发语言,是.NET平台支撑的一种。vs2017是开发工具,简单说就是编辑器,只是集成了.NET平台和各种库,这样vs2017就支撑了很多语言开发,c#,VB,java,js,vb,F#.所以vs2017变得臃肿巨大,.NET也在支撑,也在逐步增加,所以你看看,如果再提高某个方向的库,会变成什么样子。值得一说的是,其实到.NET4.0以后,基本就没有新的技术出现了,对于c#,只是提供了语法糖,编译器自动转换罢了,优势是我们自己的cs文件可能小了,编译器大了。
不多说,不然又是一堆废话,还不少。
对于一个大学生即将就业,哪个好?根据你所在的地方,能够让你就业就是好的。对于一个程序员,哪个好?哥们,别比较了,你已经有一门语言在吃饭了,对于你来说,这辈子很大可能不会只用一种语言开发。对于这么热门的数据分析和人工智能,你得学Python啊。其实语法很简单,你只需要了解库,到时网上查就是了。
最最后,前面虽然提到了混合编程,但是最好不要这么做。如果如例子那样调用c#库,既然是c#为啥不直接使用呢,还要多个Python方式,简直无语,不知道为啥会这样提供。所以一般情况是写好Python文件然后调用一个入口,返回结果就好了,混合编程完全没有必要,多次一举。
然后是注意Python库,官网Python实际是CPython.解释器是c写的,所以可以执行c代码库,但是IronPython是c#版本的,执行不了,而CPython为了速度,性能方面的优化,有些库是c的,所以打算混合开发前你要注意你的库了。还有就是前面说的IronPython现在支持2.7。3.x还不稳定,小心了。作为架构设计者,这些要注意了,最好不要混合编程,这种思路就是给自己挖坑,不到不得已的时候坚决不要有混合编程,需要填很多坑。
最后再为大家提供一个思路吧。把项目变成分布式服务。一端用c#,一端用CPython。用网络进行沟通。其实我们要用IronPython,就是因为Python有很多现成的库(某个方向,某个领域,例如前面提到的数据分析),一旦没有了,其实就没有必要了。作为设计者一定要平衡,或者用c#实现一个类似的库。这个投入就大了,就看老板的态度了,还要测试,最后还要和Python比较谁好,但愿随着c#开源,net core跨平台,有没有优秀的第三方库来支持,就😩不用考虑用IronPython了。
提一下,Python多线程不能提高速度,始终是一个线程在一刻执行,已经提供了代码优化(其实是多进程的)。
就不继续扩展了,还有些废话,就不说了,原本还打算聊聊混合编程的问题,到此打住,大家多交流吧。
完成这篇博文,居然花了好几个小时,奇怪了。边用vs2017测试。同时测试Python环境。至于JPython我就不聊了,这毕竟不是我主业。
vs2017中开发Python,推荐一篇博文设置环境。https://blog.csdn.net/manjiang8743/article/details/79517135
返回去看了看博文,差不多了,拜拜。