如果给定初始化类为PyObject,则从C ++调用Python类方法

时间:2019-03-22 14:53:49

标签: python c++ python-c-api c-api

我在c ++中有一个函数,该函数接收一个初始化的类作为PyObject。 python类是:

class Expression:
    def __init__(self, obj):
        self.obj = obj

    def get_source(self):
        #Check if the object whose source is being obtained is a function.
        if inspect.isfunction(self.obj):
            source = inspect.getsourcelines(self.obj)[0][1:]
            ls = len(source[0]) - len(source[0].lstrip())
            source = [line[ls:] for line in source]
            #get rid of comments from the source
            source = [item for item in source if item.lstrip()[0] != '#']
            source = ''.join(source)
            return source
        else:
            raise Exception("Expression object is not a function.")

c ++收到以下消息:

Expression(somefunctogetsource)

如何从c ++调用表达式对象的get_source方法? 到目前为止,我已经阅读了python c-api文档并尝试了以下操作:

PyObject* baseClass = (PyObject*)expression->ob_type;
PyObject* func = PyObject_GetAttrString(baseClass, "get_source");
PyObject* result = PyObject_CallFunctionObjArgs(func, expression, NULL);

并将结果转换为字符串,但这不起作用。

1 个答案:

答案 0 :(得分:1)

比您做的要简单。您无需直接从基类中检索任何内容。只要做:

PyObject* result = PyObject_CallMethod(expression, "get_source", NULL);
if (result == NULL) {
    // Exception occurred, return your own failure status here
}
// result is a PyObject* (in this case, it should be a PyUnicode_Object)

PyObject_CallMethod使用一个对象来调用方法,方法名称为C样式字符串,参数为格式字符串+ varargs。当不需要参数时,格式字符串可以为NULL

生成的PyObject*对于C ++代码不是超级有用(它在运行时确定1、2或4个字节的字符,具体取决于所涉及的顺序,因此将其直接复制到std::stringstd::wstring不起作用),but PyUnicode_AsUTF8AndSize can be used to get a UTF-8 encoded version and length,可用于有效构造具有等效数据的std::string

如果性能很重要,则可能需要在模块加载期间显式地制作一个表示PyObject*的{​​{1}},例如像这样的全局对象:

"get_source"

在模块的PyObject *get_source_name; 中初始化为:

PyMODINIT_FUNC

有了这些,就可以将更高效的PyObject_CallMethodObjArgs与以下命令配合使用:

get_source_name = PyUnicode_InternFromString("get_source");

节省的费用主要是避免一遍又一遍地从C PyObject* result = PyObject_CallMethodObjArgs(expression, get_source_name, NULL); 构造Python级别str,并使用char*构造字符串,这是使用Interned字符串,使查找更加有效(由于PyUnicode_InternFromString的名称本身在解释器中进行get_source -ed时会自动插入,因此不会对内容进行实际的内存比较;它意识到两个字符串都是并检查它们是否指向相同的内存。