Python C-API: How to use the returned python dictionary in Objective-C?
Python C-API: How to use the returned python dictionary in Objective-C?
My Python script app.py
has this function for example:
app.py
def testmethod(x):
return {"steps":["hello","world"]}
I am using Python C-API in Objective-C as follows:
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. 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.
myResult
PyFloat_AsDouble
PyUnicode_AsUTF8String
PyBytes_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.
Can someone help me figure out how I can convert the PyObject
to a NSDictionary?
PyObject
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. Similar to how I used PyUnicode_AsUTF8String, PyBytes_AsString and stringWithUTF8String all combined together to get a NSString out of the Python String. 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. Then in myObjective C- code, I first get the string, then use JSONObjectWithData
to convert the json string to a 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. This seems more like a workaround solution to me. Here's what I have now:
json.dumps
JSONObjectWithData
app.py:
import json
def testmethod(x):
return json.dumps({"steps":["hello","world"]})
Objective-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);
@user2357112 Yes I understand that. 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. Similar to how I used
PyUnicode_AsUTF8String
, PyBytes_AsString
and stringWithUTF8String
all combined together to get a NSString out of the Python String. Looking for something similar for dictionaries.– Pranoy C
Jul 2 at 20:05
PyUnicode_AsUTF8String
PyBytes_AsString
stringWithUTF8String
Not a direct answer, but have you looked at PyObjC ? pythonhosted.org/pyobjc
– Koen
Jul 2 at 20:07
1 Answer
1
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. Otherwise, you should try and coerce them all into native types.
PyObject*
(This is in pseudo code since I don't really know Objective-C, but have used the C-Api and 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. 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_Next
PyDict_GetItemString
char *
PyDict_GetItem
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Objective-C is not C or C++. The Python C API is a C API, not an Objective-C API; it doesn't come with functions to convert Python objects into Objective-C data structures.
– user2357112
Jul 2 at 20:03