我遇到了纯python和C python模块的情况。 总结一下,我如何在C模块中接受和操作python对象? 我的python部分看起来像这样。
#!/usr/bin/env python
import os, sys
from c_hello import *
class Hello:
busyHello = _sayhello_obj
class Man:
def __init__(self, name):
self.name = name
def getName(self):
return self.name
h = Hello()
h.busyHello( Man("John") )
在C中,需要解决两件事。 首先,我该如何接收物品? 第二,如何从对象中调用方法?
static PyObject *
_sayhello_obj(PyObject *self, PyObject *args)
{
PyObject *obj;
// How can I fill obj?
char s[1024];
// How can I fill s, from obj.getName() ?
printf("Hello, %s\n", s);
return Py_None;
}
答案 0 :(得分:10)
要从方法调用中提取参数,您需要查看Parsing arguments and building values中记录的函数,例如PyArg_ParseTuple
。 (这是因为如果你只是采取位置args!还有其他的位置和关键字args等。)
从PyArg_ParseTuple
返回的对象没有增加引用计数。对于简单的C函数,您可能不需要担心这一点。如果您正在与其他Python / C函数交互,或者您正在发布全局解释器锁(即允许线程),则需要非常仔细地考虑对象所有权。
static PyObject *
_sayhello_obj(PyObject *self, PyObject *args)
{
PyObject *obj = NULL;
// How can I fill obj?
static char fmt_string = "O" // For "object"
int parse_result = PyArg_ParseTuple(args, fmt_string, &obj);
if(!parse_res)
{
// Don't worry about using PyErr_SetString, all the exception stuff should be
// done in PyArg_ParseTuple()
return NULL;
}
// Of course, at this point you need to do your own verification of whatever
// constraints might be on your argument.
要在对象上调用方法,您需要使用PyObject_CallMethod
或PyObject_CallMethodObjArgs
,具体取决于您构造参数列表和方法名称的方式。并在有关对象所有权的代码中查看我的评论!
快速离题只是为了确保你不会让自己陷入困境:如果你真的只是将字符串输出来打印它,你最好只是获取对象引用并将其传递给{{ 3}}。当然,也许这只是为了说明,或者你比我更了解你想要做的数据;)
char s[1024];
// How can I fill s, from obj.getName() ?
// Name of the method
static char method_name = "getName";
// No arguments? Score! We just need NULL here
char method_fmt_string = NULL;
PyObject *objname = PyObject_CallMethod(obj, obj_method, method_fmt_string);
// This is really important! What we have here now is a Python object with a newly
// incremented reference count! This means you own it, and are responsible for
// decrementing the ref count when you're done. See below.
// If there's a failure, we'll get NULL
if(objname == NULL)
{
// Again, this should just propagate the exception information
return NULL;
}
现在PyObject_Print
文档的String/Bytes Objects部分中有许多功能;使用最适合你的那个。
但不要忘记这一点:
// Now that we're done with the object we obtained, decrement the reference count
Py_XDECREF(objname);
// You didn't mention whether you wanted to return a value from here, so let's just
// return the "None" singleton.
// Note: this macro includes the "return" statement!
Py_RETURN_NONE;
}
请注意Concrete Objects Layer在那里使用,请注意,它不是return Py_RETURN_NONE
!
PS。此代码的结构在很大程度上取决于个人风格(例如,函数内部的早期返回,static char
格式字符串,初始化为NULL
)。希望除了风格惯例之外,重要的信息是清晰的。