How to use a .NET method which modifies in place in Python?

后端 未结 2 890
情深已故
情深已故 2020-12-17 02:42

I am trying to use a .NET dll in Python. In a .NET language the method requires passing it 2 arrays by reference which it then modifies:

public void GetItems         


        
相关标签:
2条回答
  • 2020-12-17 03:16

    PythonNet doesn't document this quite as clearly as IronPython, but it does almost the same thing.

    So, let's look at the IronPython documentation for ref and out parameters:

    The Python language passes all arguments by-value. There is no syntax to indicate that an argument should be passed by-reference like there is in .NET languages like C# and VB.NET via the ref and out keywords. IronPython supports two ways of passing ref or out arguments to a method, an implicit way and an explicit way.

    In the implicit way, an argument is passed normally to the method call, and its (potentially) updated value is returned from the method call along with the normal return value (if any). This composes well with the Python feature of multiple return values…

    In the explicit way, you can pass an instance of clr.Reference[T] for the ref or out argument, and its Value field will get set by the call. The explicit way is useful if there are multiple overloads with ref parameters…

    There are examples for both. But to tailor it to your specific case:

    itemIDs, itemNames = GetItems()
    

    Or, if you really want:

    itemIDsRef = clr.Reference[Array[int]]()
    itemNamesRef = clr.Reference[Array[String]]()
    GetItems(itemIDs, itemNames)
    itemIDs, itemNames = itemIDsRef.Value, itemNamesRef.Value
    

    CPython using PythonNet does basically the same thing. The easy way to do out parameters is to not pass them and accept them as extra return values, and for ref parameters to pass the input values as arguments and accept the output values as extra return values. Just like IronPython's implicit solution. (Except that a void function with ref or out parameters always returns None before the ref or out arguments, even if it wouldn't in IronPython.) You can figure it out pretty easily by inspecting the return values. So, in your case:

    _, itemIDs, itemNames = GetItems()
    

    Meanwhile, the fact that these happen to be arrays doesn't make things any harder. As the docs explain, PythonNet provides the iterable interface for all IEnumerable collections, and the sequence protocol as well for Array. So, you can do this:

    for itemID, itemName in zip(itemIDs, itemNames):
        print itemID, itemName
    

    And the Int32 and String objects will be converted to native int/long and str/unicode objects just as if they were returned directly.


    If you really want to explicitly convert these to native values, you can. map or a list comprehension will give you a Python list from any iterable, including a PythonNet wrapper around an Array or other IEnumerable. And you can explicitly make a long or unicode out of an Int32 or String if you need to. So:

    itemIDs = map(int, itemIDs)
    itemNames = map(unicode, itemNames)
    

    But I don't see much advantage to doing this, unless you need to, e.g., pre-check all the values before using any of them.

    0 讨论(0)
  • 2020-12-17 03:31

    I have managed to use the method bool XferData(ref byte[] buf, ref int len) from C# library CyUSB.dll with the following code:

    >>> xferLen = 2;
    
    >>> outData=[10, 0]
    
    >>> inData=[]
    
    >>> n, outData, xferLen = XferData(outData, xferLen)
    
    >>> print n, outData[0], outData[1], xferLen
    
    True 10 0 2
    

    Hope this helps someone.

    0 讨论(0)
提交回复
热议问题