将 IronPython 集成到您的应用程序中






4.05/5 (8投票s)
本文介绍了脚本的实用性,并解释了如何将 IronPython 作为脚本语言集成到您的应用程序中。
引言
IronPython 是 .NET 的 Python 实现。它通过 Python 编程语言提供对 .NET 库的完全访问,同时也提供对标准 Python 库的访问。虽然它可以用于编写独立应用程序,但本文将重点介绍如何将其用作应用程序的脚本语言。
为什么要使用脚本语言?
- 在运行时更改功能
这有很多原因 - 也许你的每个客户都希望你的应用程序表现不同,而编写和发布插件太过麻烦。或者你的客户是开发人员,他们希望能够更改应用程序的行为并立即反馈进行自定义,而无需重新编译应用程序或插件。或者,你正在测试某些功能,并且希望应用程序在不同时间表现不同,而无需中断调试器。
- 提供“额外”功能
你正在运行你的应用程序,并注意到它占用了大量内存。你决定使用内存分析器对其进行分析,但在那之前,你想运行一个完整的 GC,以便分析器只捕获活动对象。如果有一种方法可以调用 `GC.Collect`,那不是很棒吗?或者,假设你有一个复杂的 UI,需要大量的导航,你想让开发人员省去每次都要浏览 UI 的麻烦。如果有一种东西可以自动完成所有必要的操作,并帮助开发人员快速进入有趣的部分,那不是很棒吗?
- 实时测试
单元测试非常适合单独测试各个组件,但如果你能编写可以在实时系统上运行的测试,那不是很棒吗?例如,当用户单击按钮 X 并且软件处于状态 Y 时,运行测试 Z?或者进行 UI 测试,例如自动填写文本框和单击按钮?
- 深入了解实时系统
当你被困住而没有调试器,并且想检查系统状态(例如,类成员的值)时,如果你能直接在命令窗口中输入它并立即看到结果,那不是很棒吗?
集成 IronPython
集成 IronPython 非常简单。你需要
- 从你的应用程序中添加对 IronPython.dll 的引用
- 实例化一个 `PythonEngine` 对象
- 将你想通过脚本公开的对象添加到 `pythonEngine.Globals`
- 重定向标准输出和错误流,以便你可以显示错误和脚本输出
下面的代码片段展示了如何在附加的示例应用程序中完成这些操作
public Form1()
{
InitializeComponent();
InitializeIronPython();
}
private void InitializeIronPython()
{
Options.PrivateBinding = true;
pythonEngine = new PythonEngine();
MessageBoxStream s = new MessageBoxStream();
pythonEngine.SetStandardError(s);
pythonEngine.SetStandardOutput(s);
pythonEngine.AddToPath(AppDomain.CurrentDomain.BaseDirectory);
pythonEngine.Globals.Add("form", this);
pythonEngine.Globals.Add("bl", bl);
}
`MessageBoxStream` 是一个派生自 `System.IO.Stream` 的类,它使用 `MessageBox.Show` 显示写入流的任何内容。`pythonEngine.Globals.Add` 方法将你的对象作为全局变量公开给脚本。第一个参数是 `string`,它对应于脚本中的变量名,第二个参数是与该变量对应的对象。示例应用程序将 `Form` 对象和业务逻辑对象公开给脚本。
示例应用程序底部还有一个“命令提示符”,它实际上是一个 `textbox`,用于执行实时 Python 代码。代码如下所示
private void commandPrompt_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '\r')
{
try
{
pythonEngine.ExecuteToConsole(commandPrompt.Text);
commandPrompt.Clear();
}
catch(Exception e)
{
MessageBox.Show(e.ToString());
}
}
}
它只是将文本转发到 `pythonEngine` 对象上的 `ExecuteToConsole` 方法。
使用 IronPython
附加的项目演示了如何在上一节中提到的内容。这是一个相当牵强的应用程序 - 它有两个输入 `textbox` 和一个输出 `textbox`。有三个按钮:“Add”、“Subtract”和“Custom”。正如你所期望的,Add 按钮会添加输入 `textbox` 中的数字并将其写入输出,Subtract 会减去它们,而 Custom 允许人们编写自定义操作。让我们回顾一下上一节中提到的几点,看看如何使用 IronPython 完成它们。
运行时更改功能
“Custom”按钮执行应用程序目录中的一个名为 custom.py 的脚本。该脚本获取输入 `textbox` 和 `Form` 实例的引用,它可以使用这些来执行任何自定义操作。IronPython 允许你控制脚本可以引用的对象。
private void customButton_Click(object sender, EventArgs e)
{
Dictionaryobject /> locals = new Dictionaryobject />()
{
{"input1", input1},
{"input2", input2},
};
pythonEngine.ExecuteFile("custom.py", pythonEngine.DefaultModule, locals);
}
custom.py 脚本会自动获取添加到 `pythonEngine` 对象中的全局对象。除此之外,你还可以传递一个名称/对象对的字典作为该脚本的局部变量。然后,脚本文件可以像这样访问它们:
def append(x, y):
return ''.join([x,y])
form.ShowResult(int(append(input1.Text, input2.Text)))
此脚本只需连接输入 `textbox` 中的文本,将连接结果转换为数字,然后调用 `Form` 对象的 `ShowResult`。
再举一个例子,输入以下命令:
form.TransformResult = lambda x : '-'.join(str(x))
然后执行 Add 或 Subtract - 你会注意到结果的数字之间有连字符。
如果你查看 `ShowResult` 的代码,你会发现它会在设置 `resultTextBox` 的 `Text` 属性之前调用 `TransformResult` 委托(如果可用)。上面的代码片段创建了一个匿名函数,该函数将传递的数字转换为 `string`,然后在每个字符之间插入一个连字符。然后,该匿名函数被分配给 `Form` 对象的 `TransformResult` 委托,然后在单击 Add 按钮时调用它。
提供“额外”功能
你只需在命令提示符 `textbox` 中输入 `GC.Collect` 并按 Enter,就可以立即让 CLR 执行 GC。
为了更有趣的例子,假设你作为开发人员想了解当前会话中生成的结果。假设这是你不想写进应用程序中的一部分。使用 IronPython,你可以这样做:
resultTextBox = form.Controls.Find('result', True)[0]
results = []
def fn(arg1, arg2) : results.append(resultTextBox.Text)
resultTextBox.TextChanged += fn
然后你可以在命令提示符中的任何点输入……
results
……以获取到目前为止计算出的结果。该脚本基本上订阅了 `resultTextBox` 的 `TextChanged` 事件,并将内容附加到一个列表中。
实时测试
使用上一节中显示的 `Controls.Find` 方法,你可以获取对任何 UI 对象的引用,然后对其进行操作。
input1TextBox = form.Controls.Find('input1', True)[0]
input2TextBox = form.Controls.Find('input2', True)[0]
resultTextBox = form.Controls.Find('result', True)[0]
input1TextBox.Text = '1'
input2TextBox.Text = '2'
addButton = form.Controls.Find('addButton', True)[0]
addButton.PerformClick()
print int(resultTextBox.Text) == 3
print int(resultTextBox.Text) == 4
如你所见,这段代码获取了 UI 对象的引用,设置了值,执行了一个操作,然后验证了结果。你也可以选择通过将 UI 对象添加到 `PythonEngine.Globals` 来公开它们,而不是使用 `Control.Find` 来获取它们。
深入了解实时系统
你已经看到你可以访问 UI 对象并对其进行操作。你可以做……
form.Text = 'IronPython'
……例如,更改 `form` 的标题。你也可以访问业务逻辑组件,如果你将它们添加到 PythonEngine。示例应用程序公开了它持有的 `BusinessLogic` 对象,名称为 `bl`,因此你现在也可以访问其状态。它将最后一个操作的类型作为成员,所以你可以做……
bl.LastOperation
……以查看上一次执行的操作。
结论
我希望这篇文章让你对 IronPython 和将脚本集成到你的应用程序中产生了兴趣。IronPython 项目托管在 CodePlex 上,所以那里是你下载和了解更多信息的地方。示例应用程序中的命令提示符非常基础,还有像 IronTextBox 这样的替代方案,它们做得更好。你也可以向你的提示符添加“meta”命令,允许你执行任意 Python 文件。请记住,附加的应用程序是一个**示例**应用程序,旨在演示 IronPython 集成,所以如果代码缺少错误检查,你就知道为什么了。
历史
- 2008年3月16日 15:39: 初始发布