如何使用在 Python 中就地修改的 .NET 方法?
Posted
技术标签:
【中文标题】如何使用在 Python 中就地修改的 .NET 方法?【英文标题】:How to use a .NET method which modifies in place in Python? 【发布时间】:2013-11-05 04:33:34 【问题描述】:我正在尝试在 Python 中使用 .NET dll。在 .NET 语言中,该方法需要通过引用传递 2 个数组,然后对其进行修改:
public void GetItems(
out int[] itemIDs,
out string[] itemNames
)
如何使用 Python for .NET 模块在 Python 中使用此方法?
编辑:忘了说这是在 CPython 而不是 IronPython 中。
附加信息。 当我执行以下操作时:
itemIDs = []
itemNames = []
GetItems(itemIDs, itemNames)
我得到如下输出:
(None, <System.Int32[] at 0x43466c0>, <System.String[] at 0x43461c0>)
我只需要弄清楚如何将这些转换回 python 类型吗?
【问题讨论】:
为什么要将它们转换回 Python 类型而不是仅仅使用它们? @abarnet 既然您在下面的回答中做得如此出色,我将在那里发表评论。 【参考方案1】:PythonNet 没有像 IronPython 那样清楚地记录这一点,但它几乎做了同样的事情。
那么,让我们看看ref
and out
parameters 的 IronPython 文档:
Python 语言按值传递所有参数。没有语法表明参数应该通过引用传递,就像在 .NET 语言(如 C# 和 VB.NET)中通过 ref 和 out 关键字。 IronPython 支持将 ref 或 out 参数传递给方法的两种方式,一种是隐式方式,一种是显式方式。
在隐式方式中,参数被正常传递给方法调用,其(可能)更新的值与正常返回值(如果有)一起从方法调用返回。这与 Python 的多返回值特性很好地组合在一起……
以显式方式,您可以为 ref 或 out 参数传递一个
clr.Reference[T]
的实例,其 Value 字段将由调用设置。如果有多个带有 ref 参数的重载,则显式方法很有用……
两者都有例子。但要根据您的具体情况进行调整:
itemIDs, itemNames = GetItems()
或者,如果你真的想要:
itemIDsRef = clr.Reference[Array[int]]()
itemNamesRef = clr.Reference[Array[String]]()
GetItems(itemIDs, itemNames)
itemIDs, itemNames = itemIDsRef.Value, itemNamesRef.Value
使用PythonNet 的CPython 基本上做同样的事情。处理out
参数的简单方法是不传递它们并接受它们作为额外的返回值,并且ref
参数将输入值作为参数传递并接受输出值作为额外的返回值。就像 IronPython 的隐式解决方案一样。 (除了带有ref
或out
参数的void
函数总是在ref
或out
参数之前返回None
,即使它不会在IronPython 中。)你可以很容易地弄清楚通过检查返回值。所以,在你的情况下:
_, itemIDs, itemNames = GetItems()
同时,这些恰好是数组这一事实并没有让事情变得更难。正如the docs 解释的那样,PythonNet 为所有IEnumerable
集合提供了可迭代接口,并为Array
提供了序列协议。所以,你可以这样做:
for itemID, itemName in zip(itemIDs, itemNames):
print itemID, itemName
并且Int32
和String
对象将被转换为本机int
/long
和str
/unicode
对象,就像它们被直接返回一样。
如果您真的想将这些显式转换为本机值,您可以。 map
或列表推导式将为您提供任何可迭代的 Python 列表,包括围绕 Array
或其他 IEnumerable
的 PythonNet 包装器。如果需要,您可以从Int32
或String
中显式创建long
或unicode
。所以:
itemIDs = map(int, itemIDs)
itemNames = map(unicode, itemNames)
但我认为这样做并没有多大好处,除非您需要,例如,在使用任何值之前预先检查所有值。
【讨论】:
谢谢,很遗憾我忘了说我使用的是 CPython 而不是 IronPython。 @abernet 我正在创建一些关于如何在 CPython 中使用这个 dll 的文档。我认为在某些情况下,用户会想要使用 python 对象的内置属性,否则这些属性将不可用。事实证明,如果返回是字符串、整数等,Python.Net 确实会返回 python 对象。只有当返回的对象是数组时,它才不会转换。我在我的文档中使用了列表理解作为如何将数组转换为列表的示例(同时也转换了元素的类型)。也感谢您的地图创意。 @abarnet 顺便说一句,即使参数是“输出”参数,如果我没有将任何内容传递给方法,即:_, itemIDs, itemNames = GetItems() 我收到以下错误:TypeError : 没有方法匹配给定的参数 @abarnert:例如:r, d = Double.TryParse('12.3')
不起作用,请参阅***.com/q/54692267/7556646。【参考方案2】:
我已经设法使用该方法 来自 C# 库 CyUSB.dll 的 bool XferData(ref byte[] buf, ref int len) 使用以下代码:
>>> xferLen = 2;
>>> outData=[10, 0]
>>> inData=[]
>>> n, outData, xferLen = XferData(outData, xferLen)
>>> print n, outData[0], outData[1], xferLen
True 10 0 2
希望这对某人有所帮助。
【讨论】:
以上是关于如何使用在 Python 中就地修改的 .NET 方法?的主要内容,如果未能解决你的问题,请参考以下文章