【问题标题】:Python C-API: How to use the returned python dictionary in Objective-C?Python C-API:如何在 Objective-C 中使用返回的 Python 字典?
【发布时间】:2018-07-02 19:58:18
【问题描述】:

我的 Python 脚本 app.py 有这个功能,例如:

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

我在 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

在此之后,我不确定如何转换 myResult 来检索我的字典。对于双精度和字符串,我们通常使用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]);

我对 Objective-C 没有太多经验,所以也许我没有找对地方。

如何将PyObject 转换为 NSDictionary?

我基本上是在寻找一种首先访问字典的 C 方法(例如地图),然后我可以使用 Objective-C 方法将其转换为 NSDictionary。与我使用 PyUnicode_AsUTF8String 的方式类似,PyBytes_AsString 和 stringWithUTF8String 都组合在一起以从 Python 字符串中获取 NSString。为字典寻找类似的东西。

我已经找到了实现这一目标的方法,但我不知道这是否是最好的方法。我修改了我的 python 脚本以使用 json.dumps 返回字典的字符串表示形式。然后在我的 Objective-C 代码中,我首先获取字符串,然后使用JSONObjectWithData 将 json 字符串转换为 NSDictionary。这暂时有效,但我很好奇是否有更好的方法来做到这一点,而不必从 Python 返回字符串而不是字典。这对我来说似乎更像是一种解决方法。这是我现在拥有的:

app.py:

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

目标-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);

【问题讨论】:

  • Objective-C 不是 C 或 C++。 Python C API 是 C API,而不是 Objective-C API;它没有将 Python 对象转换为 Objective-C 数据结构的函数。
  • @user2357112 是的,我明白这一点。我基本上是在寻找一种首先访问字典的 C 方法(例如地图),然后我可以使用目标 C 方法将其转换为 NSDictionary。与我使用PyUnicode_AsUTF8StringPyBytes_AsStringstringWithUTF8String 的方式类似,所有这些都组合在一起以从Python 字符串中获取一个NSString。为字典寻找类似的东西。
  • 不是一个直接的答案,但你看过 PyObjC 吗? pythonhosted.org/pyobjc

标签: python ios objective-c cpython


【解决方案1】:

使用PyDict_Next 迭代字典的键/值对。

如果您仍将使用PyObject*s,您还应该提供 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;
}

另一种选择是仅使用 Python API 来访问字典的值。因此使用PyDict_NextPyDict_GetItemString 遍历所有值以使用简单的char *s 和PyDict_GetItem 访问字符串项以访问任意Python 值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-03
    • 2016-07-05
    相关资源
    最近更新 更多