pythonnet / pythonnet

Python for .NET is a package that gives Python programmers nearly seamless integration with the .NET Common Language Runtime (CLR) and provides a powerful application scripting tool for .NET developers.
http://pythonnet.github.io
MIT License
4.77k stars 711 forks source link

c# <-> python dictionary converter #623

Closed den-run-ai closed 3 years ago

den-run-ai commented 6 years ago

https://stackoverflow.com/questions/48689604/calling-into-python-code-using-pythonnet-from-c-sharp-and-custom-c-sharp-classes

yagweb commented 6 years ago

This function is similar to the function I proposed here #484. These two functions can be integrated into single one,“How to convert between python objects and CLR objects dynamically?”

Based on my code before, I just wrote a new PyConverter here. I can make a PR if this design is accepted.

It can be used in these ways,

  1. Convert between Python list and Clr List\<T> dynamically;
  2. Convert between Python dict and Clr Dictionary<K, V> dynamically;
  3. Convert between Python object and Clr object, looks like Serialize and Deserialize.
  4. Convert any complex objects, such as nested dictionaries, lists and objects etc.
  5. It's extensible. Users can define his own PyClrType.

For this issue from stackoverflow, we can use the PyConverter in this way,

First [define a PyConverter]() according to needs,

public PyConverter NewMyDictConverter()
{
    using (Py.GIL())
    {
        var converter = new PyConverter(); 
        converter.AddListType();
        converter.Add(new StringType());
        converter.Add(new Int64Type());
        converter.Add(new Int32Type());
        converter.Add(new FloatType());
        converter.Add(new DoubleType());
        converter.AddDictType<string, object>();
        return converter;
    }
}

Then, we can use this converter to convert a Clr Dictionary into a Python Dictionary, and vice versa.


using (Py.GIL())
{  
    //create a instance of PyConverter                
    var converter = NewMyDictConverter();

    var scope = Py.CreateScope();
    scope.Exec(
         "a={'0': 1, '1': [1, \"2\"]}"
    );
    dynamic a = scope.Get("a");  // mock a python dictionary

    var b = converter.ToClr(a);   //Convert python dict to Clr Dictionary<string, object>

    var c = converter.ToPython(b);  // Convert Clr Dictionary to python dict
    object c0 = c["0"];
    object c1 = c["1"];

    var d = converter.ToClr(c);
    object d0 = d["0"];
    object d1 = d["1"];

    scope.Dispose();
}
den-run-ai commented 6 years ago

@yagweb when you mention conversion happens "dynamically", do you mean the conversion happens at runtime or even later when the corresponding value/field is accessed?

yagweb commented 6 years ago

@denfromufa "dynamically" here means the conversion happens at runtime.

It‘s opposite to "static": we know the type of the value/field in coding phase, so we directly use the PyInt etc. in the code.

There are three drawbacks of this hard coding method,

  1. We need to define lots of transformation codes which have similar structure.
  2. These codes are completely dependent on the specific data structure, so it's hard to maintenance.
  3. Sometimes we don’t know the type in coding phase, for example, for a list of type List\<object>, we don't know the types of its element until runtime.

The work steps of PyConverter are,

  1. Recognize the type of the object at runtime, or accept a given type for ‘static’ use
  2. Use the type to find a proper converter, e.g. Python int can be converted into Clr Int32/Int64 etc.
  3. Call the method and obtain the return value.
den-run-ai commented 6 years ago

@yagweb i have not tested your converter API yet, but this looks promising. regarding preparing a PR, there is too much activity currently. i would wait until we stabilize .net core support in few weeks.

kostjaaa commented 6 years ago

Have you tested this yet? It looks quite promising and I would like to use it. Would this be licensed under any terms?

den-run-ai commented 5 years ago

@kostjaaa feel free to submit a PR, but make a summary of what you would like to achieve first.

sschukat commented 5 years ago

I had a similar problem but solved it using Python code, which works with the current release See the netdict example.

lostmsu commented 3 years ago

This should now be fixed in 3.0

siegfriedpammer commented 9 months ago

This should now be fixed in 3.0

When working with a typing.Dict[str, str] and Dictionary<string, string> I still get

TypeError: 'dict' value cannot be converted to System.Collections.Generic.Dictionary`2[System.String,System.String]

on Python.NET 3.0.3

Looking at the source code it seems there is a PyDict wrapper, but it is not used in any of the Converter logic. Are there any plans to add built-in conversion support for dictionaries?

If it is supposed to work, an example show-casing the correct way to assign a python dictionary to an managed property accepting Dictionary<TKey, TValue> or IDictionary<TKey, TValue> or IReadOnlyDictionary<TKey, TValue> would be highly appreciated.

If only Python.NET was more "user-friendly"... don't get me wrong, it is doing an awesome job with most things, there are just some rough edges and unfortunately I already spent countless hours figuring out these things without much success...

Thanks!

theGEBIRGE commented 8 months ago

I would also be interested in an example.

nwoolls commented 3 weeks ago

This should now be fixed in 3.0

Any details on how this was fixed in 3.0? How are we meant to take a dictionary from python and convert it into a C# Dictionary<T,T>?