本文讲述用C#调用Ironpython运行环境,解析并运行动态pyhton脚本。这种情况应用在那些需要滞后规定行为的场合,例如,动态计算项(计算引擎),用户可以自定义计算内容、计算公式等。

本文的代码适用于IronPython 2.7(需要下载及安装)及C#4.0,由于IronPython早期版本提供的Hosting API不同,对于网上搜索得到的代码,如果是早期版本代码(多数如此),并不能编译通过,所以本文强调代码的版本问题。

本文代码需要引用两个命名空间IronPython和Microsoft.Scripting (文件位置分别为IronPython 2.7的安装目录下的IronPython.dll和Microsoft.Scripting.dll)。

一、最简单的例子

先看一个最简单的例子,C#环境与Python环境没有数据联系。

  1. public static void test1()
  2. {
  3. var engine = IronPython.Hosting.Python.CreateEngine();
  4. engine.CreateScriptSourceFromString("print 'hello world'").Execute();
  5. Console.ReadLine();
  6. }

如果IronPython环境建立好,运行test1(),就会得到正确的结果。如果只想运行一段脚本,就是这般简单。

二、C#环境调用Python环境函数

以上的例子没有实用价值,再看第二个例子,这个例子演示了如何从C#环境调用Python环境中的函数以及类中方法。

  1. public static void test2()
  2. {
  3. var engine = Python.CreateEngine();
  4. var scope = engine.CreateScope();
  5. var source = engine.CreateScriptSourceFromString(
  6. "def adder(arg1, arg2):\n" +
  7. "   return arg1 + arg2\n" +
  8. "\n" +
  9. "def fun(arg1):\n" +
  10. "   tel = {'jack': 4098, 'sape': 4139}\n" +
  11. "   for k, v in arg1.iteritems():\n"+
  12. "      tel[k]=v\n"+
  13. "   return tel\n" +
  14. "\n" +
  15. "class MyClass(object):\n" +
  16. "   def __init__(self, value):\n" +
  17. "       self.value = value\n");
  18. source.Execute(scope);
  19. var adder = scope.GetVariable<Func<object, object, object>>("adder");
  20. Console.WriteLine(adder(2, 2));
  21. var fun = scope.GetVariable<Func<object, object>>("fun");
  22. IronPython.Runtime.PythonDictionary inputDict = new IronPython.Runtime.PythonDictionary();
  23. inputDict["abc"] = "abc";
  24. inputDict["def"] = 456;
  25. object res = fun(inputDict);
  26. IronPython.Runtime.PythonDictionary outputDict = res as IronPython.Runtime.PythonDictionary;
  27. foreach (var k in outputDict.Keys)
  28. {
  29. Console.WriteLine("key:"+ k.ToString()+" val:  " + outputDict[k].ToString());
  30. }
  31. var myClass = scope.GetVariable<Func<object, object>>("MyClass");
  32. var myInstance = myClass("hello");
  33. Console.WriteLine(engine.Operations.GetMember(myInstance, "value"));
  34. }

上面代码中,python中有两个函数和一个类,第一个函数的参数是简单数据类型,第二个是复杂数据类型(关于两个环境下复杂数据类型的对应,下面将论述)。无论是类还是函数,C#的调用方法都是通过ScriptScope.GetVariable,它的函数定义如下:

T GetVariable<T>(string name);

ScriptScope还有一个更“安全”的方法

boolTryGetVariable<T>(string name, out T value);

可以完成相似的操作。

这个例子,可以扩展C#的应用,例如,python有丰富的数学计算库,而C#在这方面较欠缺,这时,就可以采用上面的方式,计算部分采用现成的python库,而主控程序采用C#编制。

三、在Python环境中调用C#环境函数

现在看第三个例子,如果Python运行逻辑复杂,需要在运行过程中调用C#函数怎么办?

  1. public static void test3()
  2. {
  3. var engine = Python.CreateEngine();
  4. var scope = engine.CreateScope();
  5. scope.SetVariable("my_object_model", new CSharpClass ());
  6. string pythonscript =
  7. "def fun(arg1):\n" +
  8. "   result = arg1+1\n" +
  9. "   return result\n" +
  10. "adder = fun(5) + my_object_model.Foo(2)\n" ;
  11. engine.CreateScriptSourceFromString(pythonscript).Execute(scope);
  12. Console.WriteLine(scope.GetVariable("adder"));
  13. }
  14. Class CSharpClass
  15. {
  16. public int Foo(int arg)
  17. {
  18. return  arg +1;
  19. }
  20. }

这个例子中,创建CShparpClass类,并将其作为“变量”传到Python环境中,在Python中就可以调用了。注意到C#中的类名可以和Python中不一样。

四、在Python环境中动态调用C#库

在这种情况下,Python脚本和C#库都是“滞后”于主应用才编写出来的,可以满足用户现场定制行为(采用Python脚本),并且可以给Python脚本传入现场定制的参数。

首先,建立一个C#库,代码如下:

  1. namespace LibforPython
  2. {
  3. public class PythonLib
  4. {
  5. public int Test(int x, string op)
  6. {
  7. switch (op.ToUpper())
  8. {
  9. case "INC":
  10. return x + 1;
  11. case "DEC":
  12. return x - 1;
  13. }
  14. return x + 1;
  15. }
  16. }
  17. }

编译成LibforPython.dll后拷贝到主运行程序的运行目录(二者同目录)。调用代码如下:

  1. public static void test4()
  2. {
  3. var engine = Python.CreateEngine();
  4. var scope = engine.CreateScope();
  5. engine.Runtime.LoadAssembly(Assembly.LoadFrom("LibforPython.dll"));              string pythonscript =
  6. "from LibforPython import PythonLib\n" +
  7. "o = PythonLib()\n" +
  8. "res = o.Test(6,'add')\n";
  9. engine.CreateScriptSourceFromString(pythonscript).Execute(scope);
  10. Console.WriteLine(scope.GetVariable("res"));
  11. }

运行以上程序即可。这个例子中,LibforPython.dll是在运行时才引入Python环境中的。对于预先已知的Python可能用到的接口,才用例三的办法更好些,对于预先无法预先定义或“遗忘”的接口,采用本例比较适合。

五、总结

将Python环境“寄宿”于C#环境,进而动态执行用户自定义的脚本,是应用可配置性、灵活性的一种体现(其他动态语言也可以这么做,以Ironpython比较简单)。这一过程包括以下三步:

var engine = Python.CreateEngine();

var scope = engine.CreateScope();

var source = engine.CreateScriptSourceFromString(“…”);

source.Execute(scope);

Python环境与宿主环境的交互(参数传入、传出),则通过ScriptScop的GetVariable和SetVariable进行。

最新文章

  1. Oracle【IT实验室】数据库备份与恢复之二:SQL*Loader
  2. C#中读写JSON风格的配置信息
  3. iOS tableview 优化总结
  4. hdu 3038 How Many Answers Are Wrong
  5. mybatis源码分析(2)——事务概述
  6. python下如何处理windows的路径名
  7. ORA-12520错误解决方法
  8. 安卓---Tabhost实现页面局部刷新--父页子页之间的传值
  9. NSCondition
  10. Hibernate---第一个helloworld程序 (XML版本, annotation版本)
  11. Spring 自定义注解,配置简单日志注解
  12. jQuery与js的length属性
  13. HBase Master 启动
  14. 第七周java学习总结
  15. 大数据平台Lambda架构详解
  16. WPF版公司的自动签到程序
  17. 图片在IE8浏览器多一个有边框问题解决办法
  18. kafka负载均衡相关资料收集(二)
  19. Ubuntu14.04更换阿里云源
  20. 初识shell expect

热门文章

  1. ArcSDE当关系查询ArcMap与REST查询结果不一致问题的解决
  2. ONVIFclient搜索设备获取rtsp解决开发笔记(精华文章)
  3. 图解:如何U盘装Win7系统(傻瓜式装机) + 分区步骤图解(用WIN7自带管理工具)
  4. RIA Test:try catch 对 Error #1009 (无法访问空对象引用的属性或方法)的处理
  5. 4.windows和Linux下创建oracleusername表空间,表,插入数据,用户管理表等操作
  6. KMP算法的Next数组详解(转)
  7. 在Mybatis中使用注解@多个參数查询
  8. Hadoop-2.2.0中国文献—— MapReduce 下一代 -- 公平调度
  9. poj1185(状压dp)
  10. OpenCL 查看设备信息