在Python中将对象传递给C模块

时间:2011-11-29 08:19:44

标签: python

我遇到了纯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;
    }

1 个答案:

答案 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_CallMethodPyObject_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)。希望除了风格惯例之外,重要的信息是清晰的。