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

Ray*_*ond 10 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") )
Run Code Online (Sandbox Code Playgroud)

在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;
    }
Run Code Online (Sandbox Code Playgroud)

det*_*tly 10

要从方法的调用中提取参数,您需要查看解析参数和构建值中记录的函数,例如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.
Run Code Online (Sandbox Code Playgroud)

要在对象上调用方法,您需要使用PyObject_CallMethodPyObject_CallMethodObjArgs,具体取决于您构造参数列表和方法名称的方式.并在有关对象所有权的代码中查看我的评论!

快速离题只是为了确保你不会让自己陷入困境:如果你真的只是将字符串输出来打印它,你最好只是获取对象引用并传递给它PyObject_Print.当然,也许这只是为了说明,或者你比我更了解你想要做的数据;)

  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;
  }
Run Code Online (Sandbox Code Playgroud)

现在,具体对象层文档的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;
}
Run Code Online (Sandbox Code Playgroud)

注意Py_RETURN_NONE那里的使用,并注意它不是return Py_RETURN_NONE!

PS.此代码的结构在很大程度上取决于个人风格(例如,早期返回,static char函数内部的格式字符串,初始化NULL).希望除了风格惯例之外,重要的信息是清晰的.