從C API中的字符串響應創建對象

[英]Create object from string repesentation in C API


I am working on a system which is embedding a Python interpreter, and I need to construct a PyObject* given a string from the C API.

我正在研究一個正在嵌入Python解釋器的系統,我需要構造一個PyObject*,給定一個來自C API的字符串。

I have a const char* representing a dictionary, in the proper format for eval() to work properly from within Python, ie: "{'bar': 42, 'baz': 50}".

我有一個const char*表示一個字典,它的格式是eval()在Python中正常工作的,即:“{'bar': 42, 'baz': 50}”。

Currently, this is being passed into Python as a PyObject* using the Py_Unicode_ api (representing a string), so in my python interpreter, I can successfully write:

目前,使用Py_Unicode_ api(表示字符串)將它作為PyObject*傳遞到Python中,因此在我的Python解釋器中,我可以成功地編寫:

foo = eval(myObject.value)
print(foo['bar']) # prints 42

I would like to change this to automatically "eval" the const char* on the C side, and return a PyObject* representing a completed dictionary. How do I go about converting this string into a dictionary in the C API?

我想將其更改為在C端自動“eval”const char*,並返回表示已完成字典的PyObject*。如何將這個字符串轉換成C API中的字典?

1 个解决方案

#1


3  

There are two basic ways to do this.

有兩種基本的方法。

The first is to simply call eval the same way you do in Python. The only trick is that you need a handle to the builtins module, because you don't get that for free in the C API. There are a number of ways to do this, but one really easy way is to just import it:

第一種方法是簡單地調用eval,就像在Python中那樣。唯一的訣竅是,您需要一個對builtins模塊的句柄,因為在C API中,您沒有得到免費的句柄。有很多方法可以做到這一點,但是一個非常簡單的方法就是導入它:

/* or PyEval_GetBuiltins() if you know you're at the interpreter's top level */
PyObject *builtins = PyImport_ImportModule("builtins");
PyObject *eval = PyObject_GetAttrString(builtins, "eval");
PyObject *args = Py_BuildValue("(s)", expression_as_c_string);
PyObject *result = PyObject_Call(eval, args);

(This is untested code, and it at least leaks references, and doesn't check for NULL return if you want to handle exceptions on the C side… But it should be enough to get the idea across.)

(這是未經測試的代碼,它至少泄露了引用,如果您希望在C端處理異常,它不會檢查NULL返回……但它應該足以讓您理解這個想法。)

One nice thing about this is that you can use ast.literal_eval in exactly the same way as eval (which means you get some free validation); just change "builtins" to "ast", and "eval" to "literal_eval". But the real win is that you're doing exactly what eval does in Python, which you already know is exactly what you wanted.

其中一個好處是,您可以使用ast.literal_eval,其方式與eval完全相同(這意味着您可以得到一些免費的驗證);只需將“builtins”更改為“ast”,“eval”更改為“literal_eval”。但真正的好處是,您所做的與eval在Python中所做的完全相同,您已經知道這正是您想要的。

The alternative is to use the compilation APIs. At the really high level, you can just build a Python statement out of "foo = eval(%s)" and PyRun_SimpleString it. Below that, use Py_CompileString to parse and compile the expression (you can also parse and compile in separate steps, but that isn't useful here), then PyEval_EvalCode to evaluate it in the appropriate globals and locals. (If you're not tracking globals yourself, use the interpreter-reflection APIs PyEval_GetLocals and PyEval_GetGlobals.) Note that I'm giving the super-simplified version of each function; often you want to use one of the sibling functions. But you can find them easily in the docs.

另一種選擇是使用編譯api。在真正的高級別上,您可以用“foo = eval(%s)”和PyRun_SimpleString構建一個Python語句。在此基礎上,使用Py_CompileString來解析和編譯表達式(您也可以在單獨的步驟中解析和編譯,但這在這里並不有用),然后PyEval_EvalCode在適當的全局變量和局部變量中進行評估。(如果您自己沒有跟蹤全局變量,請使用解釋器反射api pyeval_getlocal和PyEval_GetGlobals)。注意,我給出了每個函數的超級簡化版本;通常,您希望使用一個兄弟函數。但是你可以在文檔中找到它們。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2013/04/05/72f7179f9f015ce8076bcbbec98ffed1.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com