gpt4 book ai didi

c# - 来自 C# 的 IronPython 生成器的优雅迭代

转载 作者:太空宇宙 更新时间:2023-11-03 13:31:11 25 4
gpt4 key购买 nike

相当精通 C# 和 Python(但不了解新 dynamic .NET 4.x 中的功能),我最近决定添加 IronPython对我的一个 C# 应用程序的脚本支持。我有所有基本的通信工作,例如传递 Action<>进入并从 Python 调用到我的 C# 代码中。

但我无法从 C# 代码中找到使用 python 生成器的文档或示例。我有一个解决方案,但它远非优雅。

我在我的 python 代码(“test.py”)中定义了一个生成器:

def do_yield():
yield 1
yield 2
yield 3

在 C# 中,我设置了 IronPython 环境:

// set up IronPython
var ipy = Python.CreateRuntime();
test = ipy.UseFile("test.py");

我定义了一个辅助函数来转换返回的 PythonGenerator到 C# 迭代器,所以我的 foreach看起来像:

foreach (int n in PythonGeneratorToCSharpIterator<int>(test.do_yield()))
{
Log("py gen returned: " + n);
}

还有我的辅助函数:

IEnumerable<T> PythonGeneratorToCSharpIterator<T>(IronPython.Runtime.PythonGenerator pyGenerator)
{
while (true) {
T t = default(T);

try {
// get the next value
object o = pyGenerator.next();

// will throw an exception if it's not the correct type (or no more values in the generator)
t = (T)o;
}
catch (Exception ex) {
break; // break out of the while loop and return from the iterator
}

yield return t; // this can't be inside try/catch
}
}

python 生成器返回 LightException当没有更多值可返回时,行 t = (T)o将抛出异常,因为它试图将其转换为 int .

一个问题是我没有捕获并正确处理来自 python 代码的任何异常。我只是把它们扔掉并退出循环。另一个是当我没有来自生成器的值时抛出异常,我更喜欢 bool 检查来测试返回的值是否无效。

可能是我对新dynamic的无知.NET 的某些方面使我无法理解如何正确编写代码。在 C#/IronPython 中是否有更好/更标准的编码方式?

编辑

来自 vcsjones ' 评论,我现在有了这段代码,使用 Linq 的 Cast 对我来说效果很好。扩展方法:

var gen = (IronPython.Runtime.PythonGenerator)test.do_yield();
foreach(int n in gen.Cast<int>()) {
Log("py gen returned (with Cast): " + n);
}

最佳答案

这很容易使用 dynamic :

var ipy = Python.CreateRuntime();
dynamic test = ipy.UseFile("test.py");
foreach (int n in test.do_yield())
{
Console.WriteLine("py gen returned: " + n);
}

// outputs
py gen returned: 1
py gen returned: 2
py gen returned: 3

您应该注意的一件大事是扩展方法(如 LINQ)不适用于 dynamic ,因为扩展方法只是应用了一些语法糖的静态方法调用。和 object in this case工具 IEnumerable但不是 IEnumerable<int> ,限制了你如何处理这个问题的选择。

假设您要将项目过滤为偶数。这是一种方法:

var ipy = Python.CreateRuntime();
dynamic test = ipy.UseFile("test.py");
foreach (int n in test.do_yield())
{
if (n % 2 == 0)
Console.WriteLine("py gen returned: " + n);
}

或者您可以进行强制转换,然后使用 LINQ 扩展方法(之所以有效,是因为 IEnumerable 强制转换让其余代码在编译时被评估,就像非动态代码一样):

var ipy = Python.CreateRuntime();
dynamic test = ipy.UseFile("test.py");
foreach (int n in ((IEnumerable)test.do_yield()).Cast<int>().Where(n => n % 2 == 0))
{
Console.WriteLine("py gen returned: " + n);
}

在某些情况下,您可能希望使用没有语法糖的扩展方法,例如

// these lines are generally equivalent, unless someList is dynamic
var filteredList = Enumerable.Where(someList, x => x % 2 == 0);
var filteredList = someList.Where(x => x % 2 == 0);

关于c# - 来自 C# 的 IronPython 生成器的优雅迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20505408/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com