Python脚本和C#的互相调用

Python是一种解释型、面向对象、动态数据类型的高级程序设计语言。是一门动态解释型语言,也是一门胶水语言,很方面调用其它编程语言的程序。比如:C/C++,C#等等。这里介绍一下Python和C#的互相调用。

IronPython 是一种在 .NET 及 Mono上的 Python 实现,由微软的 Jim Hugunin 所发起,是一个开源的项目,基于微软的 DLR 引擎。

IronPython是流行的程序设计语言Python通向.NET framework的一个端口。微软公司对于.NET framework的IronPython和动态语言非常关注。微软公司已经在各种项目中提供了对IronPython的支持。

IronPython已经很好的集成到了.NET framework中,Python语言中的字符串对应于.NET的字符串对象,并且Python语言中对应的方法,在IronPython中也都提供了。其它数据类型也是一样。

IronPython-2.7.8经过了一年的制作,终于发布了。这将是第一个支持 .NET Core 的版本。一些详情的更新内容,请点击这里查看。

下载地址:

  • IronPython-2.7.8.msi

  • IronPython.2.7.8.zip

  • IronPython.StdLib.2.7.8.zip

  • Source code (zip)

  • Source code (tar.gz)

 

1.IronPython 调用 .NET 标准库

在这里我们使用VS2019进行开发,新建一个IronPython项目:

Python脚本和C#的互相调用_第1张图片

 

如上图创建一个IronPython 控制台程序,命名为IronPythonTest 。在.NET中,有很多标准库,在IronPython中,就可以使用import来引入这些标准库来直接使用。看一个简单的例子,我们使用.NET中的String和DateTime 。

Python脚本和C#的互相调用_第2张图片

上面写一个简单的Python脚本,通过 IronPython2.7 .exe 解释器执行。如下图:

Python脚本和C#的互相调用_第3张图片

2.IronPython调用 .NET  自定义库(DLL)

在.NET开发中,会经常通过References来引用一些.NET库,当然在IronPython项目中,也可以引用并使用.NET库。

例如,现在我们有一个Calc的计算类型,里面有一个Add和Sub方法。通过这个类型,生成了一个CalcLib.dll。R

​
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;
        }
    }
}

​

下面看看如何在IronPython项目中使用这个dll,在IronPython中,可以使用"clr"模块来添加.NET引用,将CalLib.dll编译好,放在IronPython 工程目录和执行脚本同一目录下:

 

Python脚本和C#的互相调用_第4张图片

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!")

IronPython解释执行:

Python脚本和C#的互相调用_第5张图片

 

3.C#调用IronPython脚本

在.NET framework中,包含了IronPython的编译器和执行引擎,所以我们可以通过C#代码创建一个引擎实例,然后执行脚本。

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

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

现在我们有一个简单的打印当前时间的IronPython脚本:

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!")

先进一个C#控制台项目,引入IronPython库:

using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                ScriptEngine engine = Python.CreateEngine();
                ScriptScope scope = engine.CreateScope();

                ScriptSource script = engine.CreateScriptSourceFromFile(@"IronPythonTest.py");

                var result = script.Execute(scope);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

        }
    }
}

将控制台exe程序输出到IronPython脚本同一目录:

Python脚本和C#的互相调用_第6张图片

点击运行,从C#程序调用了IronPython脚本(这里Exe必须和IronPython在同一目录下,才可以成功调用)

Python脚本和C#的互相调用_第7张图片

4.从C#给IronPython传递参数

在ScriptScope类型中,有一个SetVariable方法,我们可以通过这个方法给脚本传递参数。

public void SetVariable(string name, object value)

这样,我们就可以把一个C#实例传递给IronPython,然后脚本就可以使用C#实例的成员。看一个例子:

using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Test
{
    public class Student
    {
        public int Age { get; set; }
        public string Name { get; set; }
        public override string ToString()
        {
            return string.Format("{0} is {1} years old", this.Name, this.Age);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                ScriptEngine engine = Python.CreateEngine();
                ScriptScope scope = engine.CreateScope();
                Student stu = new Student { Name = "deokoo", Age = 28 };
                scope.SetVariable("stuObj",stu);
                ScriptSource script = engine.CreateScriptSourceFromFile(@"IronPythonTest.py");

                var result = script.Execute(scope);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

        }
    }

    

}

在这个例子中,C#代码中创建了一个Student类型的实例,并把这个实例传递给了PrintStuInfo.py脚本:

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)
print "Student name:", stuObj.Name
print "Student age:", stuObj.Age
print stuObj.ToString()
raw_input("press Enter to exit!")

通过输出可以看到,IronPython脚本可以方便的访问C#实例的成员:

Python脚本和C#的互相调用_第8张图片

总结

本篇文章通过一些例子演示了IronPython与C#的交互,感觉有几个例子还是很有意思的。

有时候使用C#调用IronPython可以使程序变得更加灵活,通过一个C#类型提供一组封装好的操作,每次构建类型实例然后传递给脚本;这样,用户就可以编写IronPython脚本,然后使用C#类型中提供的操作方法,从而实现不同的自定义操作。

你可能感兴趣的:(Python)