简体   繁体   English

Python C-API:如何在Objective-C 中使用返回的python 字典?

[英]Python C-API: How to use the returned python dictionary in Objective-C?

My Python script app.py has this function for example:例如,我的 Python 脚本app.py具有此功能:

def testmethod(x):
    return {"steps":["hello","world"]}

I am using Python C-API in Objective-C as follows:我在 Objective-C 中使用 Python C-API 如下:

Py_Initialize();
PyObject *pName = PyUnicode_DecodeFSDefault("app");
PyObject* pModule = PyImport_Import(pName);
Py_DECREF(pName);
        
PyObject* myFunction = PyObject_GetAttrString(pModule,(char*)"testmethod");
PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(223.22));
PyObject* myResult = PyObject_CallObject(myFunction, args);
NSLog(@"Check for dict: %d",PyDict_Check(myResult)); // Prints true!!!!!!!!!!!! So definitely a dictionary

After this, I am not really sure how I can convert the myResult to retrieve my dictionary.在此之后,我不太确定如何转换myResult以检索我的字典。 For doubles and strings, we usually use the PyFloat_AsDouble and PyUnicode_AsUTF8String , PyBytes_AsString functions but I can't seem to find a PyBLAHBLAH_AsDict or equivalent method.对于双打和字符串,我们通常使用PyFloat_AsDoublePyUnicode_AsUTF8StringPyBytes_AsString函数,但我似乎找不到PyBLAHBLAH_AsDict或等效方法。

double result = PyFloat_AsDouble(myResult);
NSLog(@"Result: %f",result);*/

PyObject* pStrObj = PyUnicode_AsUTF8String(myResult);
char* zStr = PyBytes_AsString(pStrObj);
NSLog(@"String: %@",[NSString stringWithUTF8String:zStr]);

I don't have much experience with Objective-C so maybe I am not looking at the right place.我对 Objective-C 没有太多经验,所以也许我没有看对地方。

How can I convert the PyObject to a NSDictionary?如何将PyObject转换为 NSDictionary?

I am basically looking for a C way of accessing the dictionary first (a map for example) which I can then use Objective-C methods to convert to NSDictionary.我基本上是在寻找一种首先访问字典的 C 方式(例如地图),然后我可以使用 Objective-C 方法将其转换为 NSDictionary。 Similar to how I used PyUnicode_AsUTF8String, PyBytes_AsString and stringWithUTF8String all combined together to get a NSString out of the Python String.与我使用 PyUnicode_AsUTF8String 的方式类似,PyBytes_AsString 和 stringWithUTF8String 全部组合在一起以从 Python 字符串中获取 NSString。 Looking for something similar for dictionaries.为字典寻找类似的东西。

I have figured out a way to achieve this but I don't know if this is the best possible way of doing this.我想出了一种方法来实现这一点,但我不知道这是否是最好的方法。 I modified my python script to use json.dumps to return a string representation of the dictionary.我修改了我的 python 脚本以使用json.dumps返回字典的字符串表示形式。 Then in my Objective-C code, I first get the string, then use JSONObjectWithData to convert the json string to a NSDictionary.然后在我的 Objective-C 代码中,我首先获取字符串,然后使用JSONObjectWithData将 json 字符串转换为 NSDictionary。 This works for now but I am curious if there is a better way of doing this without having to return string instead of dictionary from Python.这现在有效,但我很好奇是否有更好的方法来做到这一点,而不必从 Python 返回字符串而不是字典。 This seems more like a workaround solution to me.这对我来说更像是一种解决方法。 Here's what I have now:这是我现在所拥有的:

app.py:应用程序.py:

import json
def testmethod(x):
    return json.dumps({"steps":["hello","world"]})

Objective-C:目标-C:

Py_Initialize();
PyObject *pName = PyUnicode_DecodeFSDefault("app");
PyObject* pModule = PyImport_Import(pName);
Py_DECREF(pName);
        
PyObject* myFunction = PyObject_GetAttrString(pModule,(char*)"testmethod");
PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(223.22));
PyObject* myResult = PyObject_CallObject(myFunction, args);

PyObject* pStrObj = PyUnicode_AsUTF8String(myResult);
char* zStr = PyBytes_AsString(pStrObj);
NSString *jsonStr = [NSString stringWithUTF8String:zStr];
NSLog(@"String: %@",jsonStr);

NSError *error;
NSData *data = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];

NSLog(@"Dictionary: %@",dictionary);

Use PyDict_Next to iterate over key / value pairs of the dictionary.使用PyDict_Next迭代字典的键/值对。

You should also provide the Python hash and equality functions if you are still going to be using PyObject* s.如果您仍打算使用PyObject*您还应该提供 Python 哈希和相等函数。 Otherwise, you should try and coerce them all into native types.否则,您应该尝试将它们全部强制转换为原生类型。

(This is in pseudo code since I don't really know Objective-C, but have used the C-Api and Python) (这是伪代码,因为我不太了解 Objective-C,但使用过 C-Api 和 Python)

NSObject* convert_py_object(PyObject* obj) {
    if (PyDict_Check(obj)) return convert_py_dict(obj);
    if (PyLong_Check(obj)) return convert_py_int(obj);
    if (PyUnicode_Check(obj)) return convert_py_str(obj);
    if (PyBytes_Check(obj)) return convert_py_bytes(obj);
    if (PyList_Check(obj) || PyTuple_Check(obj) || PyIter_Check(obj)) return convert_py_list(obj);
    throw error;
}

NSDictionary* convert_py_dict(PyObject* dict) {
    if (!PyDict_Check(dict)) throw error;
    NSDictionary* native_dict;
    PyObject *key;
    PyObject *value;
    Py_ssize_t pos = 0;

    while (PyDict_Next(self->dict, &pos, &key, &value)) {
        native_dict[convert_py_object(key)] = convert_py_object(value);
    }
    return native_dict;
}

Another alternative would be to just use the Python API to access values of a dictionary.另一种选择是仅使用 Python API 来访问字典的值。 So iterate over all the values with PyDict_Next , PyDict_GetItemString to access string items with simple char * s, and PyDict_GetItem to access an arbitrary Python value.因此,使用PyDict_NextPyDict_GetItemString迭代所有值以访问具有简单char * s 的字符串项,并使用PyDict_GetItem访问任意 Python 值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM